Merge remote-tracking branch 'upstream/master' into lb_example

pull/17503/head
Juanli Shen 6 years ago
commit c771009320
  1. 4
      BUILD
  2. 531
      CMakeLists.txt
  3. 2042
      Makefile
  4. 315
      build.yaml
  5. 272
      etc/roots.pem
  6. 14
      examples/BUILD
  7. 110
      examples/cpp/compression/Makefile
  8. 84
      examples/cpp/compression/README.md
  9. 93
      examples/cpp/compression/greeter_client.cc
  10. 76
      examples/cpp/compression/greeter_server.cc
  11. 96
      examples/cpp/metadata/Makefile
  12. 66
      examples/cpp/metadata/README.md
  13. 95
      examples/cpp/metadata/greeter_client.cc
  14. 94
      examples/cpp/metadata/greeter_server.cc
  15. 6
      examples/python/metadata/README.md
  16. 134
      examples/python/metadata/helloworld_pb2.py
  17. 46
      examples/python/metadata/helloworld_pb2_grpc.py
  18. 48
      examples/python/metadata/metadata_client.py
  19. 56
      examples/python/metadata/metadata_server.py
  20. 4
      gRPC-C++.podspec
  21. 8
      gRPC-Core.podspec
  22. 23
      grpc.gyp
  23. 3
      include/grpc/grpc.h
  24. 6
      include/grpc/grpc_security_constants.h
  25. 3
      include/grpc/impl/codegen/compression_types.h
  26. 93
      include/grpcpp/alarm.h
  27. 116
      include/grpcpp/alarm_impl.h
  28. 11
      include/grpcpp/impl/codegen/byte_buffer.h
  29. 6
      include/grpcpp/impl/codegen/call_op_set.h
  30. 7
      include/grpcpp/impl/codegen/client_context.h
  31. 30
      include/grpcpp/impl/codegen/client_interceptor.h
  32. 130
      include/grpcpp/impl/codegen/interceptor.h
  33. 14
      include/grpcpp/impl/codegen/server_context.h
  34. 33
      include/grpcpp/impl/codegen/server_interceptor.h
  35. 24
      include/grpcpp/support/client_interceptor.h
  36. 24
      include/grpcpp/support/interceptor.h
  37. 24
      include/grpcpp/support/server_interceptor.h
  38. 3
      requirements.bazel.txt
  39. 75
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  40. 10
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
  41. 10
      src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
  42. 51
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  43. 47
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
  44. 70
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
  45. 17
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
  46. 19
      src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc
  47. 23
      src/core/lib/channel/channelz.cc
  48. 3
      src/core/lib/channel/channelz.h
  49. 5
      src/core/lib/channel/channelz_registry.cc
  50. 13
      src/core/lib/gprpp/memory.h
  51. 8
      src/core/lib/gprpp/ref_counted_ptr.h
  52. 195
      src/core/lib/http/httpcli_security_connector.cc
  53. 10
      src/core/lib/http/parser.h
  54. 29
      src/core/lib/iomgr/tcp_posix.cc
  55. 94
      src/core/lib/iomgr/tcp_windows.cc
  56. 183
      src/core/lib/security/context/security_context.cc
  57. 94
      src/core/lib/security/context/security_context.h
  58. 84
      src/core/lib/security/credentials/alts/alts_credentials.cc
  59. 47
      src/core/lib/security/credentials/alts/alts_credentials.h
  60. 297
      src/core/lib/security/credentials/composite/composite_credentials.cc
  61. 111
      src/core/lib/security/credentials/composite/composite_credentials.h
  62. 160
      src/core/lib/security/credentials/credentials.cc
  63. 214
      src/core/lib/security/credentials/credentials.h
  64. 117
      src/core/lib/security/credentials/fake/fake_credentials.cc
  65. 28
      src/core/lib/security/credentials/fake/fake_credentials.h
  66. 83
      src/core/lib/security/credentials/google_default/google_default_credentials.cc
  67. 33
      src/core/lib/security/credentials/google_default/google_default_credentials.h
  68. 62
      src/core/lib/security/credentials/iam/iam_credentials.cc
  69. 22
      src/core/lib/security/credentials/iam/iam_credentials.h
  70. 129
      src/core/lib/security/credentials/jwt/jwt_credentials.cc
  71. 39
      src/core/lib/security/credentials/jwt/jwt_credentials.h
  72. 2
      src/core/lib/security/credentials/jwt/jwt_verifier.cc
  73. 51
      src/core/lib/security/credentials/local/local_credentials.cc
  74. 43
      src/core/lib/security/credentials/local/local_credentials.h
  75. 279
      src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
  76. 103
      src/core/lib/security/credentials/oauth2/oauth2_credentials.h
  77. 136
      src/core/lib/security/credentials/plugin/plugin_credentials.cc
  78. 57
      src/core/lib/security/credentials/plugin/plugin_credentials.h
  79. 149
      src/core/lib/security/credentials/ssl/ssl_credentials.cc
  80. 73
      src/core/lib/security/credentials/ssl/ssl_credentials.h
  81. 329
      src/core/lib/security/security_connector/alts/alts_security_connector.cc
  82. 22
      src/core/lib/security/security_connector/alts/alts_security_connector.h
  83. 425
      src/core/lib/security/security_connector/fake/fake_security_connector.cc
  84. 15
      src/core/lib/security/security_connector/fake/fake_security_connector.h
  85. 345
      src/core/lib/security/security_connector/local/local_security_connector.cc
  86. 19
      src/core/lib/security/security_connector/local/local_security_connector.h
  87. 165
      src/core/lib/security/security_connector/security_connector.cc
  88. 207
      src/core/lib/security/security_connector/security_connector.h
  89. 718
      src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
  90. 26
      src/core/lib/security/security_connector/ssl/ssl_security_connector.h
  91. 22
      src/core/lib/security/security_connector/ssl_utils.cc
  92. 4
      src/core/lib/security/security_connector/ssl_utils.h
  93. 100
      src/core/lib/security/transport/client_auth_filter.cc
  94. 148
      src/core/lib/security/transport/security_handshaker.cc
  95. 28
      src/core/lib/security/transport/server_auth_filter.cc
  96. 59
      src/core/tsi/ssl_transport_security.cc
  97. 6
      src/cpp/client/secure_credentials.cc
  98. 9
      src/cpp/client/secure_credentials.h
  99. 13
      src/cpp/common/alarm.cc
  100. 38
      src/cpp/common/secure_auth_context.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -204,6 +204,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpc++/support/sync_stream.h",
"include/grpc++/support/time.h",
"include/grpcpp/alarm.h",
"include/grpcpp/alarm_impl.h",
"include/grpcpp/channel.h",
"include/grpcpp/client_context.h",
"include/grpcpp/completion_queue.h",
@ -243,10 +244,13 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
"include/grpcpp/support/server_interceptor.h",
"include/grpcpp/support/slice.h",
"include/grpcpp/support/status.h",
"include/grpcpp/support/status_code_enum.h",

File diff suppressed because it is too large Load Diff

2042
Makefile

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -329,36 +329,6 @@ OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
-----END CERTIFICATE-----
# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association
# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association
# Label: "Visa eCommerce Root"
# Serial: 25952180776285836048024890241505565794
# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02
# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62
# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22
-----BEGIN CERTIFICATE-----
MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw
CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h
dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l
cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h
2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E
lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV
ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq
299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t
vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL
dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF
AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3
LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw
++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
398znM/jra6O1I7mT1GvFpLgXPYHDw==
-----END CERTIFICATE-----
# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
# Subject: CN=AAA Certificate Services O=Comodo CA Limited
# Label: "Comodo AAA Services root"
@ -4340,3 +4310,245 @@ rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R1 O=Google Trust Services LLC
# Subject: CN=GTS Root R1 O=Google Trust Services LLC
# Label: "GTS Root R1"
# Serial: 146587175971765017618439757810265552097
# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85
# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8
# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX
mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7
zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P
fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc
vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4
Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp
zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO
Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW
k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+
DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF
lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW
Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z
XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR
gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3
d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv
J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg
DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM
+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy
F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9
SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws
E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R2 O=Google Trust Services LLC
# Subject: CN=GTS Root R2 O=Google Trust Services LLC
# Label: "GTS Root R2"
# Serial: 146587176055767053814479386953112547951
# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b
# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d
# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH
MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg
GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu
XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd
re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu
PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1
mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K
8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj
x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR
nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0
kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok
twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp
8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT
z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA
pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb
pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB
R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R
RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk
0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC
5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF
izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn
yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R3 O=Google Trust Services LLC
# Subject: CN=GTS Root R3 O=Google Trust Services LLC
# Label: "GTS Root R3"
# Serial: 146587176140553309517047991083707763997
# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25
# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5
# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5
-----BEGIN CERTIFICATE-----
MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A
DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk
fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA
njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd
-----END CERTIFICATE-----
# Issuer: CN=GTS Root R4 O=Google Trust Services LLC
# Subject: CN=GTS Root R4 O=Google Trust Services LLC
# Label: "GTS Root R4"
# Serial: 146587176229350439916519468929765261721
# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26
# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb
# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd
-----BEGIN CERTIFICATE-----
MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l
xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0
CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx
sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==
-----END CERTIFICATE-----
# Issuer: CN=UCA Global G2 Root O=UniTrust
# Subject: CN=UCA Global G2 Root O=UniTrust
# Label: "UCA Global G2 Root"
# Serial: 124779693093741543919145257850076631279
# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8
# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a
# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9
MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH
bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x
CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds
b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr
b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9
kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm
VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R
VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc
C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj
tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY
D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv
j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl
NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6
iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP
O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/
BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV
ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj
L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl
1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU
b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV
PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj
y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb
EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg
DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI
+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy
YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX
UB+K+wb1whnw0A==
-----END CERTIFICATE-----
# Issuer: CN=UCA Extended Validation Root O=UniTrust
# Subject: CN=UCA Extended Validation Root O=UniTrust
# Label: "UCA Extended Validation Root"
# Serial: 106100277556486529736699587978573607008
# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2
# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a
# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH
MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF
eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx
MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV
BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog
D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS
sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop
O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk
sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi
c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj
VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz
KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/
TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G
sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs
1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD
fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T
AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN
l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ
VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5
c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp
4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s
t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj
2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO
vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C
xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx
cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM
fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax
-----END CERTIFICATE-----
# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036
# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036
# Label: "Certigna Root CA"
# Serial: 269714418870597844693661054334862075617
# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77
# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43
# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68
-----BEGIN CERTIFICATE-----
MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw
WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw
MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x
MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD
VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX
BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO
ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M
CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu
I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm
TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh
C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf
ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz
IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT
Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k
JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5
hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB
GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov
L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo
dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr
aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq
hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L
6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG
HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6
0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB
lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi
o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1
gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v
faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63
Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh
jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw
3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
-----END CERTIFICATE-----

@ -52,6 +52,20 @@ cc_binary(
deps = [":helloworld", "//:grpc++"],
)
cc_binary(
name = "metadata_client",
srcs = ["cpp/metadata/greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
)
cc_binary(
name = "metadata_server",
srcs = ["cpp/metadata/greeter_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
)
cc_binary(
name = "lb_client",
srcs = ["cpp/load_balancing/greeter_client.cc"],

@ -0,0 +1,110 @@
#
# Copyright 2018 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.
#
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
SYSTEM ?= $(HOST_SYSTEM)
CXX = g++
CPPFLAGS += `pkg-config --cflags protobuf grpc`
CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
-lgrpc++_reflection\
-ldl
else
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
-ldl
endif
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
PROTOS_PATH = ../../protos
vpath %.proto $(PROTOS_PATH)
all: system-check greeter_client greeter_server
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o
$(CXX) $^ $(LDFLAGS) -o $@
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o
$(CXX) $^ $(LDFLAGS) -o $@
.PRECIOUS: %.grpc.pb.cc
%.grpc.pb.cc: %.proto
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
.PRECIOUS: %.pb.cc
%.pb.cc: %.proto
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
clean:
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
# The following is to test your system and ensure a smoother experience.
# They are by no means necessary to actually compile a grpc-enabled software.
PROTOC_CMD = which $(PROTOC)
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
ifeq ($(HAS_PROTOC),true)
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
endif
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
SYSTEM_OK = false
ifeq ($(HAS_VALID_PROTOC),true)
ifeq ($(HAS_PLUGIN),true)
SYSTEM_OK = true
endif
endif
system-check:
ifneq ($(HAS_VALID_PROTOC),true)
@echo " DEPENDENCY ERROR"
@echo
@echo "You don't have protoc 3.0.0 installed in your path."
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
@echo "You can find it here:"
@echo
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
@echo
@echo "Here is what I get when trying to evaluate your version of protoc:"
@echo
-$(PROTOC) --version
@echo
@echo
endif
ifneq ($(HAS_PLUGIN),true)
@echo " DEPENDENCY ERROR"
@echo
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
@echo "Please install grpc. You can find it here:"
@echo
@echo " https://github.com/grpc/grpc"
@echo
@echo "Here is what I get when trying to detect if you have the plugin:"
@echo
-which $(GRPC_CPP_PLUGIN)
@echo
@echo
endif
ifneq ($(SYSTEM_OK),true)
@false
endif

@ -0,0 +1,84 @@
# gRPC C++ Message Compression Tutorial
### Prerequisite
Make sure you have run the [hello world example](../helloworld) or understood the basics of gRPC. We will not dive into the details that have been discussed in the hello world example.
### Get the tutorial source code
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command:
```sh
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
```
Change your current directory to examples/cpp/compression
```sh
$ cd examples/cpp/compression/
```
### Generating gRPC code
To generate the client and server side interfaces:
```sh
$ make helloworld.grpc.pb.cc helloworld.pb.cc
```
Which internally invokes the proto-compiler as:
```sh
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
```
### Writing a client and a server
The client and the server can be based on the hello world example.
Additionally, we can configure the compression settings.
In the client, set the default compression algorithm of the channel via the channel arg.
```cpp
ChannelArguments args;
// Set the default compression algorithm for the channel.
args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP);
GreeterClient greeter(grpc::CreateCustomChannel(
"localhost:50051", grpc::InsecureChannelCredentials(), args));
```
Each call's compression configuration can be overwritten by client context.
```cpp
// Overwrite the call's compression algorithm to DEFLATE.
context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE);
```
In the server, set the default compression algorithm via the server builder.
```cpp
ServerBuilder builder;
// Set the default compression algorithm for the server.
builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP);
```
Each call's compression configuration can be overwritten by server context.
```cpp
// Overwrite the call's compression algorithm to DEFLATE.
context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE);
```
For a working example, refer to [greeter_client.cc](greeter_client.cc) and [greeter_server.cc](greeter_server.cc).
Build and run the (compressing) client and the server by the following commands.
```sh
make
./greeter_server
```
```sh
./greeter_client
```

@ -0,0 +1,93 @@
/*
*
* Copyright 2018 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.
*
*/
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ChannelArguments;
using grpc::ClientContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;
class GreeterClient {
public:
GreeterClient(std::shared_ptr<Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
// Assembles the client's payload, sends it and presents the response back
// from the server.
std::string SayHello(const std::string& user) {
// Data we are sending to the server.
HelloRequest request;
request.set_name(user);
// Container for the data we expect from the server.
HelloReply reply;
// Context for the client. It could be used to convey extra information to
// the server and/or tweak certain RPC behaviors.
ClientContext context;
// Overwrite the call's compression algorithm to DEFLATE.
context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE);
// The actual RPC.
Status status = stub_->SayHello(&context, request, &reply);
// Act upon its status.
if (status.ok()) {
return reply.message();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
}
private:
std::unique_ptr<Greeter::Stub> stub_;
};
int main(int argc, char** argv) {
// Instantiate the client. It requires a channel, out of which the actual RPCs
// are created. This channel models a connection to an endpoint (in this case,
// localhost at port 50051). We indicate that the channel isn't authenticated
// (use of InsecureChannelCredentials()).
ChannelArguments args;
// Set the default compression algorithm for the channel.
args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP);
GreeterClient greeter(grpc::CreateCustomChannel(
"localhost:50051", grpc::InsecureChannelCredentials(), args));
std::string user("world");
std::string reply = greeter.SayHello(user);
std::cout << "Greeter received: " << reply << std::endl;
return 0;
}

@ -0,0 +1,76 @@
/*
*
* Copyright 2018 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.
*
*/
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;
// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext* context, const HelloRequest* request,
HelloReply* reply) override {
// Overwrite the call's compression algorithm to DEFLATE.
context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE);
std::string prefix("Hello ");
reply->set_message(prefix + request->name());
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
GreeterServiceImpl service;
ServerBuilder builder;
// Set the default compression algorithm for the server.
builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP);
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
builder.RegisterService(&service);
// Finally assemble the server.
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
// Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();
}
int main(int argc, char** argv) {
RunServer();
return 0;
}

@ -0,0 +1,96 @@
#
# Copyright 2018 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.
#
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
SYSTEM ?= $(HOST_SYSTEM)
CXX = g++
CPPFLAGS += `pkg-config --cflags protobuf grpc`
CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
-lgrpc++_reflection\
-ldl
else
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
-ldl
endif
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
PROTOS_PATH = ../../protos
vpath %.proto $(PROTOS_PATH)
all: system-check greeter_client greeter_server
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o
$(CXX) $^ $(LDFLAGS) -o $@
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o
$(CXX) $^ $(LDFLAGS) -o $@
.PRECIOUS: %.grpc.pb.cc
%.grpc.pb.cc: %.proto
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
.PRECIOUS: %.pb.cc
%.pb.cc: %.proto
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
clean:
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
# The following is to test your system and ensure a smoother experience.
# They are by no means necessary to actually compile a grpc-enabled software.
PROTOC_CMD = which $(PROTOC)
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
ifeq ($(HAS_PROTOC),true)
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
endif
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
SYSTEM_OK = false
ifeq ($(HAS_VALID_PROTOC),true)
ifeq ($(HAS_PLUGIN),true)
SYSTEM_OK = true
endif
endif
system-check:
ifneq ($(HAS_VALID_PROTOC),true)
@echo " DEPENDENCY ERROR"
@echo
@echo "You don't have protoc 3.0.0 installed in your path."
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
@echo "You can find it here:"
@echo
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
@echo
@echo "Here is what I get when trying to evaluate your version of protoc:"
@echo
-$(PROTOC) --version
@echo
@echo
endif
ifneq ($(HAS_PLUGIN),true)
@echo " DEPENDENCY ERROR"
@echo
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
@echo "Please install grpc. You can find it here:"
@echo
@echo " https://github.com/grpc/grpc"
@echo
@echo "Here is what I get when trying to detect if you have the plugin:"
@echo
-which $(GRPC_CPP_PLUGIN)
@echo
@echo
endif
ifneq ($(SYSTEM_OK),true)
@false
endif

@ -0,0 +1,66 @@
# Metadata Example
## Overview
This example shows you how to add custom headers on the client and server and
how to access them.
Custom metadata must follow the "Custom-Metadata" format listed in
https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md, with the
exception of binary headers, which don't have to be base64 encoded.
### Get the tutorial source code
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command:
```sh
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
```
Change your current directory to examples/cpp/metadata
```sh
$ cd examples/cpp/metadata
```
### Generating gRPC code
To generate the client and server side interfaces:
```sh
$ make helloworld.grpc.pb.cc helloworld.pb.cc
```
Which internally invokes the proto-compiler as:
```sh
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
```
### Try it!
Build client and server:
```sh
$ make
```
Run the server, which will listen on port 50051:
```sh
$ ./greeter_server
```
Run the client (in a different terminal):
```sh
$ ./greeter_client
```
If things go smoothly, you will see in the client terminal:
"Client received initial metadata from server: initial metadata value"
"Client received trailing metadata from server: trailing metadata value"
"Client received message: Hello World"
And in the server terminal:
"Header key: custom-bin , value: 01234567"
"Header key: custom-header , value: Custom Value"
"Header key: user-agent , value: grpc-c++/1.16.0-dev grpc-c/6.0.0-dev (linux; chttp2; gao)"
We did not add the user-agent metadata as a custom header. This shows how
the gRPC framework adds some headers under the hood that may show up in the
metadata map.

@ -0,0 +1,95 @@
/*
*
* Copyright 2015 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.
*
*/
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;
class CustomHeaderClient {
public:
CustomHeaderClient(std::shared_ptr<Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
// Assembles the client's payload, sends it and presents the response back
// from the server.
std::string SayHello(const std::string& user) {
// Data we are sending to the server.
HelloRequest request;
request.set_name(user);
// Container for the data we expect from the server.
HelloReply reply;
// Context for the client. It could be used to convey extra information to
// the server and/or tweak certain RPC behaviors.
ClientContext context;
// Setting custom metadata to be sent to the server
context.AddMetadata("custom-header", "Custom Value");
// Setting custom binary metadata
char bytes[8] = {'\0', '\1', '\2', '\3',
'\4', '\5', '\6', '\7'};
context.AddMetadata("custom-bin", grpc::string(bytes, 8));
// The actual RPC.
Status status = stub_->SayHello(&context, request, &reply);
// Act upon its status.
if (status.ok()) {
std::cout << "Client received initial metadata from server: " << context.GetServerInitialMetadata().find("custom-server-metadata")->second << std::endl;
std::cout << "Client received trailing metadata from server: " << context.GetServerTrailingMetadata().find("custom-trailing-metadata")->second << std::endl;
return reply.message();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
}
private:
std::unique_ptr<Greeter::Stub> stub_;
};
int main(int argc, char** argv) {
// Instantiate the client. It requires a channel, out of which the actual RPCs
// are created. This channel models a connection to an endpoint (in this case,
// localhost at port 50051). We indicate that the channel isn't authenticated
// (use of InsecureChannelCredentials()).
CustomHeaderClient greeter(grpc::CreateChannel(
"localhost:50051", grpc::InsecureChannelCredentials()));
std::string user("world");
std::string reply = greeter.SayHello(user);
std::cout << "Client received message: " << reply << std::endl;
return 0;
}

@ -0,0 +1,94 @@
/*
*
* Copyright 2015 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.
*
*/
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;
// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext* context, const HelloRequest* request,
HelloReply* reply) override {
std::string prefix("Hello ");
// Get the client's initial metadata
std::cout << "Client metadata: " << std::endl;
const std::multimap<grpc::string_ref, grpc::string_ref> metadata = context->client_metadata();
for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) {
std::cout << "Header key: " << iter->first << ", value: ";
// Check for binary value
size_t isbin = iter->first.find("-bin");
if ((isbin != std::string::npos) && (isbin + 4 == iter->first.size())) {
std::cout << std::hex;
for (auto c : iter->second) {
std::cout << static_cast<unsigned int>(c);
}
std::cout << std::dec;
} else {
std::cout << iter->second;
}
std::cout << std::endl;
}
context->AddInitialMetadata("custom-server-metadata", "initial metadata value");
context->AddTrailingMetadata("custom-trailing-metadata", "trailing metadata value");
reply->set_message(prefix + request->name());
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
GreeterServiceImpl service;
ServerBuilder builder;
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
builder.RegisterService(&service);
// Finally assemble the server.
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
// Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();
}
int main(int argc, char** argv) {
RunServer();
return 0;
}

@ -0,0 +1,6 @@
An example showing how to add custom HTTP2 headers (or [metadata](https://grpc.io/grpc/python/glossary.html) in gRPC glossary)
HTTP2 supports initial headers and trailing headers, which gRPC utilizes both of them ([learn more](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)).
More complete documentation lives at [grpc.io](https://grpc.io/docs/tutorials/basic/python.html).
For API reference please see [API](https://grpc.io/grpc/python/grpc.html).

@ -0,0 +1,134 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: helloworld.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='helloworld.proto',
package='helloworld',
syntax='proto3',
serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
)
_HELLOREQUEST = _descriptor.Descriptor(
name='HelloRequest',
full_name='helloworld.HelloRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='helloworld.HelloRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=32,
serialized_end=60,
)
_HELLOREPLY = _descriptor.Descriptor(
name='HelloReply',
full_name='helloworld.HelloReply',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='message', full_name='helloworld.HelloReply.message', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=62,
serialized_end=91,
)
DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST
DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict(
DESCRIPTOR = _HELLOREQUEST,
__module__ = 'helloworld_pb2'
# @@protoc_insertion_point(class_scope:helloworld.HelloRequest)
))
_sym_db.RegisterMessage(HelloRequest)
HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict(
DESCRIPTOR = _HELLOREPLY,
__module__ = 'helloworld_pb2'
# @@protoc_insertion_point(class_scope:helloworld.HelloReply)
))
_sym_db.RegisterMessage(HelloReply)
DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
_GREETER = _descriptor.ServiceDescriptor(
name='Greeter',
full_name='helloworld.Greeter',
file=DESCRIPTOR,
index=0,
options=None,
serialized_start=93,
serialized_end=166,
methods=[
_descriptor.MethodDescriptor(
name='SayHello',
full_name='helloworld.Greeter.SayHello',
index=0,
containing_service=None,
input_type=_HELLOREQUEST,
output_type=_HELLOREPLY,
options=None,
),
])
_sym_db.RegisterServiceDescriptor(_GREETER)
DESCRIPTOR.services_by_name['Greeter'] = _GREETER
# @@protoc_insertion_point(module_scope)

@ -0,0 +1,46 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
import helloworld_pb2 as helloworld__pb2
class GreeterStub(object):
"""The greeting service definition.
"""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.SayHello = channel.unary_unary(
'/helloworld.Greeter/SayHello',
request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
response_deserializer=helloworld__pb2.HelloReply.FromString,
)
class GreeterServicer(object):
"""The greeting service definition.
"""
def SayHello(self, request, context):
"""Sends a greeting
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler(
servicer.SayHello,
request_deserializer=helloworld__pb2.HelloRequest.FromString,
response_serializer=helloworld__pb2.HelloReply.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'helloworld.Greeter', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))

@ -0,0 +1,48 @@
# Copyright 2018 The 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.
"""Example gRPC client that gets/sets metadata (HTTP2 headers)"""
from __future__ import print_function
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
with grpc.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response, call = stub.SayHello.with_call(
helloworld_pb2.HelloRequest(name='you'),
metadata=(
('initial-metadata-1', 'The value should be str'),
('binary-metadata-bin',
b'With -bin surffix, the value can be bytes'),
('accesstoken', 'gRPC Python is great'),
))
print("Greeter client received: " + response.message)
for key, value in call.trailing_metadata():
print('Greeter client received trailing metadata: key=%s value=%s' %
(key, value))
if __name__ == '__main__':
logging.basicConfig()
run()

@ -0,0 +1,56 @@
# Copyright 2018 The 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.
"""Example gRPC server that gets/sets metadata (HTTP2 headers)"""
from __future__ import print_function
from concurrent import futures
import time
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
for key, value in context.invocation_metadata():
print('Received initial metadata: key=%s value=%s' % (key, value))
context.set_trailing_metadata((
('checksum-bin', b'I agree'),
('retry', 'false'),
))
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
logging.basicConfig()
serve()

@ -78,6 +78,7 @@ Pod::Spec.new do |s|
ss.header_mappings_dir = 'include/grpcpp'
ss.source_files = 'include/grpcpp/alarm.h',
'include/grpcpp/alarm_impl.h',
'include/grpcpp/channel.h',
'include/grpcpp/client_context.h',
'include/grpcpp/completion_queue.h',
@ -115,10 +116,13 @@ Pod::Spec.new do |s|
'include/grpcpp/support/byte_buffer.h',
'include/grpcpp/support/channel_arguments.h',
'include/grpcpp/support/client_callback.h',
'include/grpcpp/support/client_interceptor.h',
'include/grpcpp/support/config.h',
'include/grpcpp/support/interceptor.h',
'include/grpcpp/support/proto_buffer_reader.h',
'include/grpcpp/support/proto_buffer_writer.h',
'include/grpcpp/support/server_callback.h',
'include/grpcpp/support/server_interceptor.h',
'include/grpcpp/support/slice.h',
'include/grpcpp/support/status.h',
'include/grpcpp/support/status_code_enum.h',

@ -1198,15 +1198,14 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Interface", version
ss.dependency "#{s.name}/Implementation", version
ss.source_files = 'test/core/util/test_config.cc',
'test/core/util/test_config.h',
'test/core/end2end/data/client_certs.cc',
ss.source_files = 'test/core/end2end/data/client_certs.cc',
'test/core/end2end/data/server1_cert.cc',
'test/core/end2end/data/server1_key.cc',
'test/core/end2end/data/test_root_cert.cc',
'test/core/security/oauth2_utils.cc',
'test/core/end2end/cq_verifier.cc',
'test/core/end2end/fixtures/http_proxy_fixture.cc',
'test/core/end2end/fixtures/local_util.cc',
'test/core/end2end/fixtures/proxy.cc',
'test/core/iomgr/endpoint_tests.cc',
'test/core/util/debugger_macros.cc',
@ -1223,6 +1222,7 @@ Pod::Spec.new do |s|
'test/core/util/slice_splitter.cc',
'test/core/util/subprocess_posix.cc',
'test/core/util/subprocess_windows.cc',
'test/core/util/test_config.cc',
'test/core/util/tracer_util.cc',
'test/core/util/trickle_endpoint.cc',
'test/core/util/cmdline.cc',
@ -1233,6 +1233,7 @@ Pod::Spec.new do |s|
'test/core/security/oauth2_utils.h',
'test/core/end2end/cq_verifier.h',
'test/core/end2end/fixtures/http_proxy_fixture.h',
'test/core/end2end/fixtures/local_util.h',
'test/core/end2end/fixtures/proxy.h',
'test/core/iomgr/endpoint_tests.h',
'test/core/util/debugger_macros.h',
@ -1247,6 +1248,7 @@ Pod::Spec.new do |s|
'test/core/util/port_server_client.h',
'test/core/util/slice_splitter.h',
'test/core/util/subprocess.h',
'test/core/util/test_config.h',
'test/core/util/tracer_util.h',
'test/core/util/trickle_endpoint.h',
'test/core/util/cmdline.h',

@ -258,16 +258,6 @@
'src/core/lib/profiling/stap_timers.cc',
],
},
{
'target_name': 'gpr_test_util',
'type': 'static_library',
'dependencies': [
'gpr',
],
'sources': [
'test/core/util/test_config.cc',
],
},
{
'target_name': 'grpc',
'type': 'static_library',
@ -604,7 +594,6 @@
'target_name': 'grpc_test_util',
'type': 'static_library',
'dependencies': [
'gpr_test_util',
'gpr',
'grpc',
],
@ -617,6 +606,7 @@
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'test/core/end2end/cq_verifier.cc',
'test/core/end2end/fixtures/http_proxy_fixture.cc',
'test/core/end2end/fixtures/local_util.cc',
'test/core/end2end/fixtures/proxy.cc',
'test/core/iomgr/endpoint_tests.cc',
'test/core/util/debugger_macros.cc',
@ -633,6 +623,7 @@
'test/core/util/slice_splitter.cc',
'test/core/util/subprocess_posix.cc',
'test/core/util/subprocess_windows.cc',
'test/core/util/test_config.cc',
'test/core/util/tracer_util.cc',
'test/core/util/trickle_endpoint.cc',
'test/core/util/cmdline.cc',
@ -850,13 +841,13 @@
'type': 'static_library',
'dependencies': [
'gpr',
'gpr_test_util',
'grpc_unsecure',
],
'sources': [
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'test/core/end2end/cq_verifier.cc',
'test/core/end2end/fixtures/http_proxy_fixture.cc',
'test/core/end2end/fixtures/local_util.cc',
'test/core/end2end/fixtures/proxy.cc',
'test/core/iomgr/endpoint_tests.cc',
'test/core/util/debugger_macros.cc',
@ -873,6 +864,7 @@
'test/core/util/slice_splitter.cc',
'test/core/util/subprocess_posix.cc',
'test/core/util/subprocess_windows.cc',
'test/core/util/test_config.cc',
'test/core/util/tracer_util.cc',
'test/core/util/trickle_endpoint.cc',
'test/core/util/cmdline.cc',
@ -1351,7 +1343,6 @@
'test_tcp_server',
'grpc_test_util',
'grpc',
'gpr_test_util',
'gpr',
],
'sources': [
@ -1364,7 +1355,6 @@
'dependencies': [
'grpc_test_util',
'grpc',
'gpr_test_util',
'gpr',
],
'sources': [
@ -1681,7 +1671,6 @@
'grpc_test_util',
'grpc++',
'grpc',
'gpr_test_util',
'gpr',
'grpc++_test_config',
],
@ -1716,7 +1705,6 @@
'grpc_test_util',
'grpc++',
'grpc',
'gpr_test_util',
'gpr',
'grpc++_test_config',
],
@ -2669,7 +2657,6 @@
'dependencies': [
'grpc_test_util_unsecure',
'grpc_unsecure',
'gpr_test_util',
'gpr',
],
'sources': [
@ -2682,7 +2669,6 @@
'dependencies': [
'grpc_test_util',
'grpc',
'gpr_test_util',
'gpr',
],
'sources': [
@ -2774,7 +2760,6 @@
'dependencies': [
'grpc_test_util_unsecure',
'grpc_unsecure',
'gpr_test_util',
'gpr',
],
'sources': [

@ -511,7 +511,8 @@ GRPCAPI char* grpc_channelz_get_server(intptr_t server_id);
/* Gets all server sockets that exist in the server. */
GRPCAPI char* grpc_channelz_get_server_sockets(intptr_t server_id,
intptr_t start_socket_id);
intptr_t start_socket_id,
intptr_t max_results);
/* Returns a single Channel, or else a NOT_FOUND code. The returned string
is allocated and must be freed by the application. */

@ -106,10 +106,10 @@ typedef enum {
} grpc_ssl_client_certificate_request_type;
/**
* Type of local connection for which local channel/server credentials will be
* applied. It only supports UDS for now.
* Type of local connections for which local channel/server credentials will be
* applied. It supports UDS and local TCP connections.
*/
typedef enum { UDS = 0 } grpc_local_connect_type;
typedef enum { UDS = 0, LOCAL_TCP } grpc_local_connect_type;
#ifdef __cplusplus
}

@ -52,7 +52,8 @@ extern "C" {
"grpc.compression_enabled_algorithms_bitset"
/** \} */
/** The various compression algorithms supported by gRPC */
/** The various compression algorithms supported by gRPC (not sorted by
* compression level) */
typedef enum {
GRPC_COMPRESS_NONE = 0,
GRPC_COMPRESS_DEFLATE,

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,99 +16,14 @@
*
*/
/// An Alarm posts the user provided tag to its associated completion queue upon
/// expiry or cancellation.
#ifndef GRPCPP_ALARM_H
#define GRPCPP_ALARM_H
#include <functional>
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/time.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/alarm_impl.h>
namespace grpc {
/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
class Alarm : private GrpcLibraryCodegen {
public:
/// Create an unset completion queue alarm
Alarm();
/// Destroy the given completion queue alarm, cancelling it in the process.
~Alarm();
/// DEPRECATED: Create and set a completion queue alarm instance associated to
/// \a cq.
/// This form is deprecated because it is inherently racy.
/// \internal We rely on the presence of \a cq for grpc initialization. If \a
/// cq were ever to be removed, a reference to a static
/// internal::GrpcLibraryInitializer instance would need to be introduced
/// here. \endinternal.
template <typename T>
Alarm(CompletionQueue* cq, const T& deadline, void* tag) : Alarm() {
SetInternal(cq, TimePoint<T>(deadline).raw_time(), tag);
}
/// Trigger an alarm instance on completion queue \a cq at the specified time.
/// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
/// an event with tag \a tag will be added to \a cq. If the alarm expired, the
/// event's success bit will be true, false otherwise (ie, upon cancellation).
template <typename T>
void Set(CompletionQueue* cq, const T& deadline, void* tag) {
SetInternal(cq, TimePoint<T>(deadline).raw_time(), tag);
}
/// Alarms aren't copyable.
Alarm(const Alarm&) = delete;
Alarm& operator=(const Alarm&) = delete;
/// Alarms are movable.
Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; }
Alarm& operator=(Alarm&& rhs) {
alarm_ = rhs.alarm_;
rhs.alarm_ = nullptr;
return *this;
}
/// Cancel a completion queue alarm. Calling this function over an alarm that
/// has already fired has no effect.
void Cancel();
/// NOTE: class experimental_type is not part of the public API of this class
/// TODO(vjpai): Move these contents to the public API of Alarm when
/// they are no longer experimental
class experimental_type {
public:
explicit experimental_type(Alarm* alarm) : alarm_(alarm) {}
/// Set an alarm to invoke callback \a f. The argument to the callback
/// states whether the alarm expired at \a deadline (true) or was cancelled
/// (false)
template <typename T>
void Set(const T& deadline, std::function<void(bool)> f) {
alarm_->SetInternal(TimePoint<T>(deadline).raw_time(), std::move(f));
}
private:
Alarm* alarm_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
experimental_type experimental() { return experimental_type(this); }
private:
void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag);
void SetInternal(gpr_timespec deadline, std::function<void(bool)> f);
internal::CompletionQueueTag* alarm_;
};
} // namespace grpc
typedef ::grpc_impl::Alarm Alarm;
}
#endif // GRPCPP_ALARM_H

@ -0,0 +1,116 @@
/*
*
* Copyright 2015 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.
*
*/
/// An Alarm posts the user provided tag to its associated completion queue upon
/// expiry or cancellation.
#ifndef GRPCPP_ALARM_IMPL_H
#define GRPCPP_ALARM_IMPL_H
#include <functional>
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/time.h>
#include <grpcpp/impl/grpc_library.h>
namespace grpc_impl {
/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
class Alarm : private ::grpc::GrpcLibraryCodegen {
public:
/// Create an unset completion queue alarm
Alarm();
/// Destroy the given completion queue alarm, cancelling it in the process.
~Alarm();
/// DEPRECATED: Create and set a completion queue alarm instance associated to
/// \a cq.
/// This form is deprecated because it is inherently racy.
/// \internal We rely on the presence of \a cq for grpc initialization. If \a
/// cq were ever to be removed, a reference to a static
/// internal::GrpcLibraryInitializer instance would need to be introduced
/// here. \endinternal.
template <typename T>
Alarm(::grpc::CompletionQueue* cq, const T& deadline, void* tag) : Alarm() {
SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag);
}
/// Trigger an alarm instance on completion queue \a cq at the specified time.
/// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
/// an event with tag \a tag will be added to \a cq. If the alarm expired, the
/// event's success bit will be true, false otherwise (ie, upon cancellation).
template <typename T>
void Set(::grpc::CompletionQueue* cq, const T& deadline, void* tag) {
SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag);
}
/// Alarms aren't copyable.
Alarm(const Alarm&) = delete;
Alarm& operator=(const Alarm&) = delete;
/// Alarms are movable.
Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; }
Alarm& operator=(Alarm&& rhs) {
alarm_ = rhs.alarm_;
rhs.alarm_ = nullptr;
return *this;
}
/// Cancel a completion queue alarm. Calling this function over an alarm that
/// has already fired has no effect.
void Cancel();
/// NOTE: class experimental_type is not part of the public API of this class
/// TODO(vjpai): Move these contents to the public API of Alarm when
/// they are no longer experimental
class experimental_type {
public:
explicit experimental_type(Alarm* alarm) : alarm_(alarm) {}
/// Set an alarm to invoke callback \a f. The argument to the callback
/// states whether the alarm expired at \a deadline (true) or was cancelled
/// (false)
template <typename T>
void Set(const T& deadline, std::function<void(bool)> f) {
alarm_->SetInternal(::grpc::TimePoint<T>(deadline).raw_time(),
std::move(f));
}
private:
Alarm* alarm_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
experimental_type experimental() { return experimental_type(this); }
private:
void SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline,
void* tag);
void SetInternal(gpr_timespec deadline, std::function<void(bool)> f);
::grpc::internal::CompletionQueueTag* alarm_;
};
} // namespace grpc_impl
#endif // GRPCPP_ALARM_IMPL_H

@ -93,7 +93,9 @@ class ByteBuffer final {
}
/// Constuct a byte buffer by referencing elements of existing buffer
/// \a buf. Wrapper of core function grpc_byte_buffer_copy
/// \a buf. Wrapper of core function grpc_byte_buffer_copy . This is not
/// a deep copy; it is just a referencing. As a result, its performance is
/// size-independent.
ByteBuffer(const ByteBuffer& buf);
~ByteBuffer() {
@ -102,6 +104,9 @@ class ByteBuffer final {
}
}
/// Wrapper of core function grpc_byte_buffer_copy . This is not
/// a deep copy; it is just a referencing. As a result, its performance is
/// size-independent.
ByteBuffer& operator=(const ByteBuffer&);
/// Dump (read) the buffer contents into \a slices.
@ -117,7 +122,9 @@ class ByteBuffer final {
/// Make a duplicate copy of the internals of this byte
/// buffer so that we have our own owned version of it.
/// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable
/// bbuf.Duplicate(); is equivalent to bbuf=bbuf; but is actually readable.
/// This is not a deep copy; it is a referencing and its performance
/// is size-independent.
void Duplicate() {
buffer_ = g_core_codegen_interface->grpc_byte_buffer_copy(buffer_);
}

@ -325,7 +325,11 @@ class CallOpSendMessage {
}
void SetFinishInterceptionHookPoint(
InterceptorBatchMethodsImpl* interceptor_methods) {}
InterceptorBatchMethodsImpl* interceptor_methods) {
// The contents of the SendMessage value that was previously set
// has had its references stolen by core's operations
interceptor_methods->SetSendMessage(nullptr);
}
void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
hijacked_ = true;

@ -200,6 +200,13 @@ class ClientContext {
/// end in "-bin".
/// \param meta_value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value);

@ -38,9 +38,17 @@ class InterceptorBatchMethodsImpl;
namespace experimental {
class ClientRpcInfo;
// A factory interface for creation of client interceptors. A vector of
// factories can be provided at channel creation which will be used to create a
// new vector of client interceptors per RPC. Client interceptor authors should
// create a subclass of ClientInterceptorFactorInterface which creates objects
// of their interceptors.
class ClientInterceptorFactoryInterface {
public:
virtual ~ClientInterceptorFactoryInterface() {}
// Returns a pointer to an Interceptor object on successful creation, nullptr
// otherwise. If nullptr is returned, this server interceptor factory is
// ignored for the purposes of that RPC.
virtual Interceptor* CreateClientInterceptor(ClientRpcInfo* info) = 0;
};
} // namespace experimental
@ -50,11 +58,16 @@ extern experimental::ClientInterceptorFactoryInterface*
g_global_client_interceptor_factory;
}
/// ClientRpcInfo represents the state of a particular RPC as it
/// appears to an interceptor. It is created and owned by the library and
/// passed to the CreateClientInterceptor method of the application's
/// ClientInterceptorFactoryInterface implementation
namespace experimental {
class ClientRpcInfo {
public:
// TODO(yashykt): Stop default-constructing ClientRpcInfo and remove UNKNOWN
// from the list of possible Types.
/// Type categorizes RPCs by unary or streaming type
enum class Type {
UNARY,
CLIENT_STREAMING,
@ -65,13 +78,23 @@ class ClientRpcInfo {
~ClientRpcInfo(){};
// Delete copy constructor but allow default move constructor
ClientRpcInfo(const ClientRpcInfo&) = delete;
ClientRpcInfo(ClientRpcInfo&&) = default;
// Getter methods
/// Return the fully-specified method name
const char* method() const { return method_; }
/// Return a pointer to the channel on which the RPC is being sent
ChannelInterface* channel() { return channel_; }
/// Return a pointer to the underlying ClientContext structure associated
/// with the RPC to support features that apply to it
grpc::ClientContext* client_context() { return ctx_; }
/// Return the type of the RPC (unary or a streaming flavor)
Type type() const { return type_; }
private:
@ -120,8 +143,11 @@ class ClientRpcInfo {
}
for (auto it = creators.begin() + interceptor_pos; it != creators.end();
++it) {
interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
(*it)->CreateClientInterceptor(this)));
auto* interceptor = (*it)->CreateClientInterceptor(this);
if (interceptor != nullptr) {
interceptors_.push_back(
std::unique_ptr<experimental::Interceptor>(interceptor));
}
}
if (internal::g_global_client_interceptor_factory != nullptr) {
interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(

@ -31,99 +31,141 @@ class ChannelInterface;
class Status;
namespace experimental {
class InterceptedMessage {
public:
template <class M>
bool Extract(M* msg); // returns false if definitely invalid extraction
template <class M>
M* MutableExtract();
uint64_t length(); // length on wire
};
/// An enumeration of different possible points at which the \a Intercept
/// method of the \a Interceptor interface may be called. Any given call
/// to \a Intercept will include one or more of these hook points, and
/// each hook point makes certain types of information available to the
/// interceptor.
/// In these enumeration names, PRE_SEND means that an interception has taken
/// place between the time the application provided a certain type of data
/// (e.g., initial metadata, status) and the time that that data goes to the
/// other side. POST_SEND means that the data has been committed for going to
/// the other side (even if it has not yet been received at the other side).
/// PRE_RECV means an interception between the time that a certain
/// operation has been requested and it is available. POST_RECV means that a
/// result is available but has not yet been passed back to the application.
enum class InterceptionHookPoints {
/* The first two in this list are for clients and servers */
/// The first two in this list are for clients and servers
PRE_SEND_INITIAL_METADATA,
PRE_SEND_MESSAGE,
PRE_SEND_STATUS /* server only */,
PRE_SEND_CLOSE /* client only */,
/* The following three are for hijacked clients only and can only be
registered by the global interceptor */
PRE_SEND_STATUS, // server only
PRE_SEND_CLOSE, // client only: WritesDone for stream; after write in unary
/// The following three are for hijacked clients only and can only be
/// registered by the global interceptor
PRE_RECV_INITIAL_METADATA,
PRE_RECV_MESSAGE,
PRE_RECV_STATUS,
/* The following two are for all clients and servers */
/// The following two are for all clients and servers
POST_RECV_INITIAL_METADATA,
POST_RECV_MESSAGE,
POST_RECV_STATUS /* client only */,
POST_RECV_CLOSE /* server only */,
/* This is a special hook point available to both clients and servers when
TryCancel() is performed.
- No other hook points will be present along with this.
- It is illegal for an interceptor to block/delay this operation.
- ALL interceptors see this hook point irrespective of whether the RPC was
hijacked or not. */
POST_RECV_STATUS, // client only
POST_RECV_CLOSE, // server only
/// This is a special hook point available to both clients and servers when
/// TryCancel() is performed.
/// - No other hook points will be present along with this.
/// - It is illegal for an interceptor to block/delay this operation.
/// - ALL interceptors see this hook point irrespective of whether the
/// RPC was hijacked or not.
PRE_SEND_CANCEL,
NUM_INTERCEPTION_HOOKS
};
/// Class that is passed as an argument to the \a Intercept method
/// of the application's \a Interceptor interface implementation. It has five
/// purposes:
/// 1. Indicate which hook points are present at a specific interception
/// 2. Allow an interceptor to inform the library that an RPC should
/// continue to the next stage of its processing (which may be another
/// interceptor or the main path of the library)
/// 3. Allow an interceptor to hijack the processing of the RPC (only for
/// client-side RPCs with PRE_SEND_INITIAL_METADATA) so that it does not
/// proceed with normal processing beyond that stage
/// 4. Access the relevant fields of an RPC at each interception point
/// 5. Set some fields of an RPC at each interception point, when possible
class InterceptorBatchMethods {
public:
virtual ~InterceptorBatchMethods(){};
// Queries to check whether the current batch has an interception hook point
// of type \a type
/// Determine whether the current batch has an interception hook point
/// of type \a type
virtual bool QueryInterceptionHookPoint(InterceptionHookPoints type) = 0;
// Calling this will signal that the interceptor is done intercepting the
// current batch of the RPC.
// Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning
// from the Intercept method does the job of continuing the RPC in this case.
/// Signal that the interceptor is done intercepting the current batch of the
/// RPC. Every interceptor must either call Proceed or Hijack on each
/// interception. In most cases, only Proceed will be used. Explicit use of
/// Proceed is what enables interceptors to delay the processing of RPCs
/// while they perform other work.
/// Proceed is a no-op if the batch contains PRE_SEND_CANCEL. Simply returning
/// from the Intercept method does the job of continuing the RPC in this case.
/// This is because PRE_SEND_CANCEL is always in a separate batch and is not
/// allowed to be delayed.
virtual void Proceed() = 0;
// Calling this indicates that the interceptor has hijacked the RPC (only
// valid if the batch contains send_initial_metadata on the client side)
/// Indicate that the interceptor has hijacked the RPC (only valid if the
/// batch contains send_initial_metadata on the client side). Later
/// interceptors in the interceptor list will not be called. Later batches
/// on the same RPC will go through interception, but only up to the point
/// of the hijacking interceptor.
virtual void Hijack() = 0;
// Returns a modifable ByteBuffer holding serialized form of the message to be
// sent
/// Returns a modifable ByteBuffer holding the serialized form of the message
/// that is going to be sent. Valid for PRE_SEND_MESSAGE interceptions.
/// A return value of nullptr indicates that this ByteBuffer is not valid.
virtual ByteBuffer* GetSendMessage() = 0;
// Returns a modifiable multimap of the initial metadata to be sent
/// Returns a modifiable multimap of the initial metadata to be sent. Valid
/// for PRE_SEND_INITIAL_METADATA interceptions. A value of nullptr indicates
/// that this field is not valid.
virtual std::multimap<grpc::string, grpc::string>*
GetSendInitialMetadata() = 0;
// Returns the status to be sent
/// Returns the status to be sent. Valid for PRE_SEND_STATUS interceptions.
virtual Status GetSendStatus() = 0;
// Modifies the status with \a status
/// Overwrites the status with \a status. Valid for PRE_SEND_STATUS
/// interceptions.
virtual void ModifySendStatus(const Status& status) = 0;
// Returns a modifiable multimap of the trailing metadata to be sent
/// Returns a modifiable multimap of the trailing metadata to be sent. Valid
/// for PRE_SEND_STATUS interceptions. A value of nullptr indicates
/// that this field is not valid.
virtual std::multimap<grpc::string, grpc::string>*
GetSendTrailingMetadata() = 0;
// Returns a pointer to the modifiable received message. Note that the message
// is already deserialized
/// Returns a pointer to the modifiable received message. Note that the
/// message is already deserialized but the type is not set; the interceptor
/// should static_cast to the appropriate type before using it. This is valid
/// for POST_RECV_MESSAGE interceptions; nullptr for not valid
virtual void* GetRecvMessage() = 0;
// Returns a modifiable multimap of the received initial metadata
/// Returns a modifiable multimap of the received initial metadata.
/// Valid for POST_RECV_INITIAL_METADATA interceptions; nullptr if not valid
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
GetRecvInitialMetadata() = 0;
// Returns a modifiable view of the received status
/// Returns a modifiable view of the received status on POST_RECV_STATUS
/// interceptions; nullptr if not valid.
virtual Status* GetRecvStatus() = 0;
// Returns a modifiable multimap of the received trailing metadata
/// Returns a modifiable multimap of the received trailing metadata on
/// POST_RECV_STATUS interceptions; nullptr if not valid
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
GetRecvTrailingMetadata() = 0;
// Gets an intercepted channel. When a call is started on this interceptor,
// only interceptors after the current interceptor are created from the
// factory objects registered with the channel.
/// Gets an intercepted channel. When a call is started on this interceptor,
/// only interceptors after the current interceptor are created from the
/// factory objects registered with the channel. This allows calls to be
/// started from interceptors without infinite regress through the interceptor
/// list.
virtual std::unique_ptr<ChannelInterface> GetInterceptedChannel() = 0;
};
/// Interface for an interceptor. Interceptor authors must create a class
/// that derives from this parent class.
class Interceptor {
public:
virtual ~Interceptor() {}
/// The one public method of an Interceptor interface. Override this to
/// trigger the desired actions at the hook points described above.
virtual void Intercept(InterceptorBatchMethods* methods) = 0;
};

@ -131,6 +131,13 @@ class ServerContext {
/// end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
/// Add the (\a key, \a value) pair to the initial metadata
@ -145,6 +152,13 @@ class ServerContext {
/// it must end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
/// IsCancelled is always safe to call when using sync or callback API.

@ -37,25 +37,47 @@ class InterceptorBatchMethodsImpl;
namespace experimental {
class ServerRpcInfo;
// A factory interface for creation of server interceptors. A vector of
// factories can be provided to ServerBuilder which will be used to create a new
// vector of server interceptors per RPC. Server interceptor authors should
// create a subclass of ServerInterceptorFactorInterface which creates objects
// of their interceptors.
class ServerInterceptorFactoryInterface {
public:
virtual ~ServerInterceptorFactoryInterface() {}
// Returns a pointer to an Interceptor object on successful creation, nullptr
// otherwise. If nullptr is returned, this server interceptor factory is
// ignored for the purposes of that RPC.
virtual Interceptor* CreateServerInterceptor(ServerRpcInfo* info) = 0;
};
/// ServerRpcInfo represents the state of a particular RPC as it
/// appears to an interceptor. It is created and owned by the library and
/// passed to the CreateServerInterceptor method of the application's
/// ServerInterceptorFactoryInterface implementation
class ServerRpcInfo {
public:
/// Type categorizes RPCs by unary or streaming type
enum class Type { UNARY, CLIENT_STREAMING, SERVER_STREAMING, BIDI_STREAMING };
~ServerRpcInfo(){};
// Delete all copy and move constructors and assignments
ServerRpcInfo(const ServerRpcInfo&) = delete;
ServerRpcInfo(ServerRpcInfo&&) = default;
ServerRpcInfo& operator=(ServerRpcInfo&&) = default;
ServerRpcInfo& operator=(const ServerRpcInfo&) = delete;
ServerRpcInfo(ServerRpcInfo&&) = delete;
ServerRpcInfo& operator=(ServerRpcInfo&&) = delete;
// Getter methods
/// Return the fully-specified method name
const char* method() const { return method_; }
/// Return the type of the RPC (unary or a streaming flavor)
Type type() const { return type_; }
/// Return a pointer to the underlying ServerContext structure associated
/// with the RPC to support features that apply to it
grpc::ServerContext* server_context() { return ctx_; }
private:
@ -90,8 +112,11 @@ class ServerRpcInfo {
std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
creators) {
for (const auto& creator : creators) {
interceptors_.push_back(std::unique_ptr<experimental::Interceptor>(
creator->CreateServerInterceptor(this)));
auto* interceptor = creator->CreateServerInterceptor(this);
if (interceptor != nullptr) {
interceptors_.push_back(
std::unique_ptr<experimental::Interceptor>(interceptor));
}
}
}

@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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.
*
*/
#ifndef GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H
#define GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H
#include <grpcpp/impl/codegen/client_interceptor.h>
#endif // GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H

@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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.
*
*/
#ifndef GRPCPP_SUPPORT_INTERCEPTOR_H
#define GRPCPP_SUPPORT_INTERCEPTOR_H
#include <grpcpp/impl/codegen/interceptor.h>
#endif // GRPCPP_SUPPORT_INTERCEPTOR_H

@ -0,0 +1,24 @@
/*
*
* Copyright 2015 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.
*
*/
#ifndef GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H
#define GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H
#include <grpcpp/impl/codegen/server_interceptor.h>
#endif // GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H

@ -9,7 +9,8 @@ futures>=2.2.0
google-auth>=1.0.0
oauth2client==4.1.0
requests>=2.14.2
urllib3==1.22
urllib3>=1.23
chardet==3.0.4
certifi==2017.4.17
idna==2.7
googleapis-common-protos==1.5.5

@ -361,7 +361,9 @@ void lb_token_destroy(void* token) {
}
}
int lb_token_cmp(void* token1, void* token2) {
return GPR_ICMP(token1, token2);
// Always indicate a match, since we don't want this channel arg to
// affect the subchannel's key in the index.
return 0;
}
const grpc_arg_pointer_vtable lb_token_arg_vtable = {
lb_token_copy, lb_token_destroy, lb_token_cmp};
@ -422,7 +424,7 @@ ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) {
grpc_resolved_address addr;
ParseServer(server, &addr);
// LB token processing.
void* lb_token;
grpc_mdelem lb_token;
if (server->has_load_balance_token) {
const size_t lb_token_max_length =
GPR_ARRAY_SIZE(server->load_balance_token);
@ -430,9 +432,7 @@ ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) {
strnlen(server->load_balance_token, lb_token_max_length);
grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer(
server->load_balance_token, lb_token_length);
lb_token =
(void*)grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr)
.payload;
lb_token = grpc_mdelem_from_slices(GRPC_MDSTR_LB_TOKEN, lb_token_mdstr);
} else {
char* uri = grpc_sockaddr_to_uri(&addr);
gpr_log(GPR_INFO,
@ -440,14 +440,16 @@ ServerAddressList ProcessServerlist(const grpc_grpclb_serverlist* serverlist) {
"be used instead",
uri);
gpr_free(uri);
lb_token = (void*)GRPC_MDELEM_LB_TOKEN_EMPTY.payload;
lb_token = GRPC_MDELEM_LB_TOKEN_EMPTY;
}
// Add address.
grpc_arg arg = grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN), lb_token,
&lb_token_arg_vtable);
const_cast<char*>(GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN),
(void*)lb_token.payload, &lb_token_arg_vtable);
grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1);
addresses.emplace_back(addr, args);
// Clean up.
GRPC_MDELEM_UNREF(lb_token);
}
return addresses;
}
@ -525,8 +527,7 @@ void GrpcLb::BalancerCallState::Orphan() {
void GrpcLb::BalancerCallState::StartQuery() {
GPR_ASSERT(lb_call_ != nullptr);
if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO,
"[grpclb %p] Starting LB call (lb_calld: %p, lb_call: %p)",
gpr_log(GPR_INFO, "[grpclb %p] lb_calld=%p: Starting LB call %p",
grpclb_policy_.get(), this, lb_call_);
}
// Create the ops.
@ -670,8 +671,9 @@ void GrpcLb::BalancerCallState::SendClientLoadReportLocked() {
grpc_call_error call_error = grpc_call_start_batch_and_execute(
lb_call_, &op, 1, &client_load_report_closure_);
if (GPR_UNLIKELY(call_error != GRPC_CALL_OK)) {
gpr_log(GPR_ERROR, "[grpclb %p] call_error=%d", grpclb_policy_.get(),
call_error);
gpr_log(GPR_ERROR,
"[grpclb %p] lb_calld=%p call_error=%d sending client load report",
grpclb_policy_.get(), this, call_error);
GPR_ASSERT(GRPC_CALL_OK == call_error);
}
}
@ -732,15 +734,17 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
&initial_response->client_stats_report_interval));
if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO,
"[grpclb %p] Received initial LB response message; "
"client load reporting interval = %" PRId64 " milliseconds",
grpclb_policy, lb_calld->client_stats_report_interval_);
"[grpclb %p] lb_calld=%p: Received initial LB response "
"message; client load reporting interval = %" PRId64
" milliseconds",
grpclb_policy, lb_calld,
lb_calld->client_stats_report_interval_);
}
} else if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO,
"[grpclb %p] Received initial LB response message; client load "
"reporting NOT enabled",
grpclb_policy);
"[grpclb %p] lb_calld=%p: Received initial LB response message; "
"client load reporting NOT enabled",
grpclb_policy, lb_calld);
}
grpc_grpclb_initial_response_destroy(initial_response);
lb_calld->seen_initial_response_ = true;
@ -750,15 +754,17 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
GPR_ASSERT(lb_calld->lb_call_ != nullptr);
if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO,
"[grpclb %p] Serverlist with %" PRIuPTR " servers received",
grpclb_policy, serverlist->num_servers);
"[grpclb %p] lb_calld=%p: Serverlist with %" PRIuPTR
" servers received",
grpclb_policy, lb_calld, serverlist->num_servers);
for (size_t i = 0; i < serverlist->num_servers; ++i) {
grpc_resolved_address addr;
ParseServer(serverlist->servers[i], &addr);
char* ipport;
grpc_sockaddr_to_string(&ipport, &addr, false);
gpr_log(GPR_INFO, "[grpclb %p] Serverlist[%" PRIuPTR "]: %s",
grpclb_policy, i, ipport);
gpr_log(GPR_INFO,
"[grpclb %p] lb_calld=%p: Serverlist[%" PRIuPTR "]: %s",
grpclb_policy, lb_calld, i, ipport);
gpr_free(ipport);
}
}
@ -778,9 +784,9 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
if (grpc_grpclb_serverlist_equals(grpclb_policy->serverlist_, serverlist)) {
if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO,
"[grpclb %p] Incoming server list identical to current, "
"ignoring.",
grpclb_policy);
"[grpclb %p] lb_calld=%p: Incoming server list identical to "
"current, ignoring.",
grpclb_policy, lb_calld);
}
grpc_grpclb_destroy_serverlist(serverlist);
} else { // New serverlist.
@ -806,8 +812,9 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
char* response_slice_str =
grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX);
gpr_log(GPR_ERROR,
"[grpclb %p] Invalid LB response received: '%s'. Ignoring.",
grpclb_policy, response_slice_str);
"[grpclb %p] lb_calld=%p: Invalid LB response received: '%s'. "
"Ignoring.",
grpclb_policy, lb_calld, response_slice_str);
gpr_free(response_slice_str);
}
grpc_slice_unref_internal(response_slice);
@ -838,9 +845,9 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked(
char* status_details =
grpc_slice_to_c_string(lb_calld->lb_call_status_details_);
gpr_log(GPR_INFO,
"[grpclb %p] Status from LB server received. Status = %d, details "
"= '%s', (lb_calld: %p, lb_call: %p), error '%s'",
grpclb_policy, lb_calld->lb_call_status_, status_details, lb_calld,
"[grpclb %p] lb_calld=%p: Status from LB server received. "
"Status = %d, details = '%s', (lb_call: %p), error '%s'",
grpclb_policy, lb_calld, lb_calld->lb_call_status_, status_details,
lb_calld->lb_call_, grpc_error_string(error));
gpr_free(status_details);
}
@ -1592,6 +1599,10 @@ void GrpcLb::CreateRoundRobinPolicyLocked(const Args& args) {
this);
return;
}
if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO, "[grpclb %p] Created new RR policy %p", this,
rr_policy_.get());
}
// TODO(roth): We currently track this ref manually. Once the new
// ClosureRef API is done, pass the RefCountedPtr<> along with the closure.
auto self = Ref(DEBUG_LOCATION, "on_rr_reresolution_requested");
@ -1685,10 +1696,6 @@ void GrpcLb::CreateOrUpdateRoundRobinPolicyLocked() {
lb_policy_args.client_channel_factory = client_channel_factory();
lb_policy_args.args = args;
CreateRoundRobinPolicyLocked(lb_policy_args);
if (grpc_lb_glb_trace.enabled()) {
gpr_log(GPR_INFO, "[grpclb %p] Created new RR policy %p", this,
rr_policy_.get());
}
}
grpc_channel_args_destroy(args);
}

@ -88,22 +88,18 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
// bearer token credentials.
grpc_channel_credentials* channel_credentials =
grpc_channel_credentials_find_in_args(args);
grpc_channel_credentials* creds_sans_call_creds = nullptr;
grpc_core::RefCountedPtr<grpc_channel_credentials> creds_sans_call_creds;
if (channel_credentials != nullptr) {
creds_sans_call_creds =
grpc_channel_credentials_duplicate_without_call_credentials(
channel_credentials);
channel_credentials->duplicate_without_call_credentials();
GPR_ASSERT(creds_sans_call_creds != nullptr);
args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS;
args_to_add[num_args_to_add++] =
grpc_channel_credentials_to_arg(creds_sans_call_creds);
grpc_channel_credentials_to_arg(creds_sans_call_creds.get());
}
grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
// Clean up.
grpc_channel_args_destroy(args);
if (creds_sans_call_creds != nullptr) {
grpc_channel_credentials_unref(creds_sans_call_creds);
}
return result;
}

@ -87,22 +87,18 @@ grpc_channel_args* grpc_lb_policy_xds_modify_lb_channel_args(
// bearer token credentials.
grpc_channel_credentials* channel_credentials =
grpc_channel_credentials_find_in_args(args);
grpc_channel_credentials* creds_sans_call_creds = nullptr;
grpc_core::RefCountedPtr<grpc_channel_credentials> creds_sans_call_creds;
if (channel_credentials != nullptr) {
creds_sans_call_creds =
grpc_channel_credentials_duplicate_without_call_credentials(
channel_credentials);
channel_credentials->duplicate_without_call_credentials();
GPR_ASSERT(creds_sans_call_creds != nullptr);
args_to_remove[num_args_to_remove++] = GRPC_ARG_CHANNEL_CREDENTIALS;
args_to_add[num_args_to_add++] =
grpc_channel_credentials_to_arg(creds_sans_call_creds);
grpc_channel_credentials_to_arg(creds_sans_call_creds.get());
}
grpc_channel_args* result = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
// Clean up.
grpc_channel_args_destroy(args);
if (creds_sans_call_creds != nullptr) {
grpc_channel_credentials_unref(creds_sans_call_creds);
}
return result;
}

@ -170,7 +170,7 @@ AresDnsResolver::AresDnsResolver(const ResolverArgs& args)
}
AresDnsResolver::~AresDnsResolver() {
gpr_log(GPR_DEBUG, "destroying AresDnsResolver");
GRPC_CARES_TRACE_LOG("resolver:%p destroying AresDnsResolver", this);
if (resolved_result_ != nullptr) {
grpc_channel_args_destroy(resolved_result_);
}
@ -182,7 +182,8 @@ AresDnsResolver::~AresDnsResolver() {
void AresDnsResolver::NextLocked(grpc_channel_args** target_result,
grpc_closure* on_complete) {
gpr_log(GPR_DEBUG, "AresDnsResolver::NextLocked() is called.");
GRPC_CARES_TRACE_LOG("resolver:%p AresDnsResolver::NextLocked() is called.",
this);
GPR_ASSERT(next_completion_ == nullptr);
next_completion_ = on_complete;
target_result_ = target_result;
@ -225,12 +226,14 @@ void AresDnsResolver::ShutdownLocked() {
void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
AresDnsResolver* r = static_cast<AresDnsResolver*>(arg);
GRPC_CARES_TRACE_LOG(
"%p re-resolution timer fired. error: %s. shutdown_initiated_: %d", r,
grpc_error_string(error), r->shutdown_initiated_);
"resolver:%p re-resolution timer fired. error: %s. shutdown_initiated_: "
"%d",
r, grpc_error_string(error), r->shutdown_initiated_);
r->have_next_resolution_timer_ = false;
if (error == GRPC_ERROR_NONE && !r->shutdown_initiated_) {
if (!r->resolving_) {
GRPC_CARES_TRACE_LOG("%p start resolving due to re-resolution timer", r);
GRPC_CARES_TRACE_LOG(
"resolver:%p start resolving due to re-resolution timer", r);
r->StartResolvingLocked();
}
}
@ -327,8 +330,8 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
service_config_string = ChooseServiceConfig(r->service_config_json_);
gpr_free(r->service_config_json_);
if (service_config_string != nullptr) {
gpr_log(GPR_INFO, "selected service config choice: %s",
service_config_string);
GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s",
r, service_config_string);
args_to_remove[num_args_to_remove++] = GRPC_ARG_SERVICE_CONFIG;
args_to_add[num_args_to_add++] = grpc_channel_arg_string_create(
(char*)GRPC_ARG_SERVICE_CONFIG, service_config_string);
@ -344,11 +347,11 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
r->backoff_.Reset();
} else if (!r->shutdown_initiated_) {
const char* msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed: %s", r, msg);
grpc_millis next_try = r->backoff_.NextAttemptTime();
grpc_millis timeout = next_try - ExecCtx::Get()->Now();
gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
grpc_error_string(error));
GRPC_CARES_TRACE_LOG("resolver:%p dns resolution failed (will retry): %s",
r, grpc_error_string(error));
GPR_ASSERT(!r->have_next_resolution_timer_);
r->have_next_resolution_timer_ = true;
// TODO(roth): We currently deal with this ref manually. Once the
@ -357,9 +360,10 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
RefCountedPtr<Resolver> self = r->Ref(DEBUG_LOCATION, "retry-timer");
self.release();
if (timeout > 0) {
gpr_log(GPR_DEBUG, "retrying in %" PRId64 " milliseconds", timeout);
GRPC_CARES_TRACE_LOG("resolver:%p retrying in %" PRId64 " milliseconds",
r, timeout);
} else {
gpr_log(GPR_DEBUG, "retrying immediately");
GRPC_CARES_TRACE_LOG("resolver:%p retrying immediately", r);
}
grpc_timer_init(&r->next_resolution_timer_, next_try,
&r->on_next_resolution_);
@ -385,10 +389,10 @@ void AresDnsResolver::MaybeStartResolvingLocked() {
if (ms_until_next_resolution > 0) {
const grpc_millis last_resolution_ago =
grpc_core::ExecCtx::Get()->Now() - last_resolution_timestamp_;
gpr_log(GPR_DEBUG,
"In cooldown from last resolution (from %" PRId64
" ms ago). Will resolve again in %" PRId64 " ms",
last_resolution_ago, ms_until_next_resolution);
GRPC_CARES_TRACE_LOG(
"resolver:%p In cooldown from last resolution (from %" PRId64
" ms ago). Will resolve again in %" PRId64 " ms",
this, last_resolution_ago, ms_until_next_resolution);
have_next_resolution_timer_ = true;
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
@ -405,7 +409,6 @@ void AresDnsResolver::MaybeStartResolvingLocked() {
}
void AresDnsResolver::StartResolvingLocked() {
gpr_log(GPR_DEBUG, "Start resolving.");
// TODO(roth): We currently deal with this ref manually. Once the
// new closure API is done, find a way to track this ref with the timer
// callback as part of the type system.
@ -420,6 +423,8 @@ void AresDnsResolver::StartResolvingLocked() {
request_service_config_ ? &service_config_json_ : nullptr,
query_timeout_ms_, combiner());
last_resolution_timestamp_ = grpc_core::ExecCtx::Get()->Now();
GRPC_CARES_TRACE_LOG("resolver:%p Started resolving. pending_request_:%p",
this, pending_request_);
}
void AresDnsResolver::MaybeFinishNextLocked() {
@ -427,7 +432,8 @@ void AresDnsResolver::MaybeFinishNextLocked() {
*target_result_ = resolved_result_ == nullptr
? nullptr
: grpc_channel_args_copy(resolved_result_);
gpr_log(GPR_DEBUG, "AresDnsResolver::MaybeFinishNextLocked()");
GRPC_CARES_TRACE_LOG("resolver:%p AresDnsResolver::MaybeFinishNextLocked()",
this);
GRPC_CLOSURE_SCHED(next_completion_, GRPC_ERROR_NONE);
next_completion_ = nullptr;
published_version_ = resolved_version_;
@ -465,11 +471,16 @@ static grpc_error* blocking_resolve_address_ares(
static grpc_address_resolver_vtable ares_resolver = {
grpc_resolve_address_ares, blocking_resolve_address_ares};
static bool should_use_ares(const char* resolver_env) {
return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0;
}
void grpc_resolver_dns_ares_init() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
/* TODO(zyc): Turn on c-ares based resolver by default after the address
sorter and the CNAME support are added. */
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
if (should_use_ares(resolver_env)) {
gpr_log(GPR_DEBUG, "Using ares dns resolver");
address_sorting_init();
grpc_error* error = grpc_ares_init();
if (error != GRPC_ERROR_NONE) {
@ -489,7 +500,7 @@ void grpc_resolver_dns_ares_init() {
void grpc_resolver_dns_ares_shutdown() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
if (resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0) {
if (should_use_ares(resolver_env)) {
address_sorting_shutdown();
grpc_ares_cleanup();
}

@ -90,15 +90,18 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver);
static grpc_ares_ev_driver* grpc_ares_ev_driver_ref(
grpc_ares_ev_driver* ev_driver) {
gpr_log(GPR_DEBUG, "Ref ev_driver %" PRIuPTR, (uintptr_t)ev_driver);
GRPC_CARES_TRACE_LOG("request:%p Ref ev_driver %p", ev_driver->request,
ev_driver);
gpr_ref(&ev_driver->refs);
return ev_driver;
}
static void grpc_ares_ev_driver_unref(grpc_ares_ev_driver* ev_driver) {
gpr_log(GPR_DEBUG, "Unref ev_driver %" PRIuPTR, (uintptr_t)ev_driver);
GRPC_CARES_TRACE_LOG("request:%p Unref ev_driver %p", ev_driver->request,
ev_driver);
if (gpr_unref(&ev_driver->refs)) {
gpr_log(GPR_DEBUG, "destroy ev_driver %" PRIuPTR, (uintptr_t)ev_driver);
GRPC_CARES_TRACE_LOG("request:%p destroy ev_driver %p", ev_driver->request,
ev_driver);
GPR_ASSERT(ev_driver->fds == nullptr);
GRPC_COMBINER_UNREF(ev_driver->combiner, "free ares event driver");
ares_destroy(ev_driver->channel);
@ -108,7 +111,8 @@ static void grpc_ares_ev_driver_unref(grpc_ares_ev_driver* ev_driver) {
}
static void fd_node_destroy_locked(fd_node* fdn) {
gpr_log(GPR_DEBUG, "delete fd: %s", fdn->grpc_polled_fd->GetName());
GRPC_CARES_TRACE_LOG("request:%p delete fd: %s", fdn->ev_driver->request,
fdn->grpc_polled_fd->GetName());
GPR_ASSERT(!fdn->readable_registered);
GPR_ASSERT(!fdn->writable_registered);
GPR_ASSERT(fdn->already_shutdown);
@ -136,7 +140,7 @@ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver,
memset(&opts, 0, sizeof(opts));
opts.flags |= ARES_FLAG_STAYOPEN;
int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS);
gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create_locked");
GRPC_CARES_TRACE_LOG("request:%p grpc_ares_ev_driver_create_locked", request);
if (status != ARES_SUCCESS) {
char* err_msg;
gpr_asprintf(&err_msg, "Failed to init ares channel. C-ares error: %s",
@ -203,8 +207,9 @@ static fd_node* pop_fd_node_locked(fd_node** head, ares_socket_t as) {
static void on_timeout_locked(void* arg, grpc_error* error) {
grpc_ares_ev_driver* driver = static_cast<grpc_ares_ev_driver*>(arg);
GRPC_CARES_TRACE_LOG(
"ev_driver=%p on_timeout_locked. driver->shutting_down=%d. err=%s",
driver, driver->shutting_down, grpc_error_string(error));
"request:%p ev_driver=%p on_timeout_locked. driver->shutting_down=%d. "
"err=%s",
driver->request, driver, driver->shutting_down, grpc_error_string(error));
if (!driver->shutting_down && error == GRPC_ERROR_NONE) {
grpc_ares_ev_driver_shutdown_locked(driver);
}
@ -216,7 +221,8 @@ static void on_readable_locked(void* arg, grpc_error* error) {
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
fdn->readable_registered = false;
gpr_log(GPR_DEBUG, "readable on %s", fdn->grpc_polled_fd->GetName());
GRPC_CARES_TRACE_LOG("request:%p readable on %s", fdn->ev_driver->request,
fdn->grpc_polled_fd->GetName());
if (error == GRPC_ERROR_NONE) {
do {
ares_process_fd(ev_driver->channel, as, ARES_SOCKET_BAD);
@ -239,7 +245,8 @@ static void on_writable_locked(void* arg, grpc_error* error) {
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
fdn->writable_registered = false;
gpr_log(GPR_DEBUG, "writable on %s", fdn->grpc_polled_fd->GetName());
GRPC_CARES_TRACE_LOG("request:%p writable on %s", ev_driver->request,
fdn->grpc_polled_fd->GetName());
if (error == GRPC_ERROR_NONE) {
ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, as);
} else {
@ -278,7 +285,8 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
fdn->grpc_polled_fd =
ev_driver->polled_fd_factory->NewGrpcPolledFdLocked(
socks[i], ev_driver->pollset_set, ev_driver->combiner);
gpr_log(GPR_DEBUG, "new fd: %s", fdn->grpc_polled_fd->GetName());
GRPC_CARES_TRACE_LOG("request:%p new fd: %s", ev_driver->request,
fdn->grpc_polled_fd->GetName());
fdn->ev_driver = ev_driver;
fdn->readable_registered = false;
fdn->writable_registered = false;
@ -295,8 +303,9 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
if (ARES_GETSOCK_READABLE(socks_bitmask, i) &&
!fdn->readable_registered) {
grpc_ares_ev_driver_ref(ev_driver);
gpr_log(GPR_DEBUG, "notify read on: %s",
fdn->grpc_polled_fd->GetName());
GRPC_CARES_TRACE_LOG("request:%p notify read on: %s",
ev_driver->request,
fdn->grpc_polled_fd->GetName());
fdn->grpc_polled_fd->RegisterForOnReadableLocked(&fdn->read_closure);
fdn->readable_registered = true;
}
@ -304,8 +313,9 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
// has not been registered with this socket.
if (ARES_GETSOCK_WRITABLE(socks_bitmask, i) &&
!fdn->writable_registered) {
gpr_log(GPR_DEBUG, "notify write on: %s",
fdn->grpc_polled_fd->GetName());
GRPC_CARES_TRACE_LOG("request:%p notify write on: %s",
ev_driver->request,
fdn->grpc_polled_fd->GetName());
grpc_ares_ev_driver_ref(ev_driver);
fdn->grpc_polled_fd->RegisterForOnWriteableLocked(
&fdn->write_closure);
@ -332,7 +342,8 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
// If the ev driver has no working fd, all the tasks are done.
if (new_list == nullptr) {
ev_driver->working = false;
gpr_log(GPR_DEBUG, "ev driver stop working");
GRPC_CARES_TRACE_LOG("request:%p ev driver stop working",
ev_driver->request);
}
}
@ -345,9 +356,9 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) {
? GRPC_MILLIS_INF_FUTURE
: ev_driver->query_timeout_ms + grpc_core::ExecCtx::Get()->Now();
GRPC_CARES_TRACE_LOG(
"ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in %" PRId64
" ms",
ev_driver, timeout);
"request:%p ev_driver=%p grpc_ares_ev_driver_start_locked. timeout in "
"%" PRId64 " ms",
ev_driver->request, ev_driver, timeout);
grpc_ares_ev_driver_ref(ev_driver);
grpc_timer_init(&ev_driver->query_timeout, timeout,
&ev_driver->on_timeout_locked);

@ -96,11 +96,11 @@ static void log_address_sorting_list(const ServerAddressList& addresses,
for (size_t i = 0; i < addresses.size(); i++) {
char* addr_str;
if (grpc_sockaddr_to_string(&addr_str, &addresses[i].address(), true)) {
gpr_log(GPR_DEBUG, "c-ares address sorting: %s[%" PRIuPTR "]=%s",
gpr_log(GPR_INFO, "c-ares address sorting: %s[%" PRIuPTR "]=%s",
input_output_str, i, addr_str);
gpr_free(addr_str);
} else {
gpr_log(GPR_DEBUG,
gpr_log(GPR_INFO,
"c-ares address sorting: %s[%" PRIuPTR "]=<unprintable>",
input_output_str, i);
}
@ -209,10 +209,10 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts,
addresses.emplace_back(&addr, addr_len, args);
char output[INET6_ADDRSTRLEN];
ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN);
gpr_log(GPR_DEBUG,
"c-ares resolver gets a AF_INET6 result: \n"
" addr: %s\n port: %d\n sin6_scope_id: %d\n",
output, ntohs(hr->port), addr.sin6_scope_id);
GRPC_CARES_TRACE_LOG(
"request:%p c-ares resolver gets a AF_INET6 result: \n"
" addr: %s\n port: %d\n sin6_scope_id: %d\n",
r, output, ntohs(hr->port), addr.sin6_scope_id);
break;
}
case AF_INET: {
@ -226,10 +226,10 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts,
addresses.emplace_back(&addr, addr_len, args);
char output[INET_ADDRSTRLEN];
ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN);
gpr_log(GPR_DEBUG,
"c-ares resolver gets a AF_INET result: \n"
" addr: %s\n port: %d\n",
output, ntohs(hr->port));
GRPC_CARES_TRACE_LOG(
"request:%p c-ares resolver gets a AF_INET result: \n"
" addr: %s\n port: %d\n",
r, output, ntohs(hr->port));
break;
}
}
@ -252,9 +252,9 @@ static void on_hostbyname_done_locked(void* arg, int status, int timeouts,
static void on_srv_query_done_locked(void* arg, int status, int timeouts,
unsigned char* abuf, int alen) {
grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
gpr_log(GPR_DEBUG, "on_query_srv_done_locked");
GRPC_CARES_TRACE_LOG("request:%p on_query_srv_done_locked", r);
if (status == ARES_SUCCESS) {
gpr_log(GPR_DEBUG, "on_query_srv_done_locked ARES_SUCCESS");
GRPC_CARES_TRACE_LOG("request:%p on_query_srv_done_locked ARES_SUCCESS", r);
struct ares_srv_reply* reply;
const int parse_status = ares_parse_srv_reply(abuf, alen, &reply);
if (parse_status == ARES_SUCCESS) {
@ -297,9 +297,9 @@ static const char g_service_config_attribute_prefix[] = "grpc_config=";
static void on_txt_done_locked(void* arg, int status, int timeouts,
unsigned char* buf, int len) {
gpr_log(GPR_DEBUG, "on_txt_done_locked");
char* error_msg;
grpc_ares_request* r = static_cast<grpc_ares_request*>(arg);
GRPC_CARES_TRACE_LOG("request:%p on_txt_done_locked", r);
const size_t prefix_len = sizeof(g_service_config_attribute_prefix) - 1;
struct ares_txt_ext* result = nullptr;
struct ares_txt_ext* reply = nullptr;
@ -332,7 +332,8 @@ static void on_txt_done_locked(void* arg, int status, int timeouts,
service_config_len += result->length;
}
(*r->service_config_json_out)[service_config_len] = '\0';
gpr_log(GPR_INFO, "found service config: %s", *r->service_config_json_out);
GRPC_CARES_TRACE_LOG("request:%p found service config: %s", r,
*r->service_config_json_out);
}
// Clean up.
ares_free_data(reply);
@ -358,12 +359,6 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
grpc_error* error = GRPC_ERROR_NONE;
grpc_ares_hostbyname_request* hr = nullptr;
ares_channel* channel = nullptr;
/* TODO(zyc): Enable tracing after #9603 is checked in */
/* if (grpc_dns_trace) {
gpr_log(GPR_DEBUG, "resolve_address (blocking): name=%s, default_port=%s",
name, default_port);
} */
/* parse name, splitting it into host and port parts */
char* host;
char* port;
@ -388,7 +383,7 @@ void grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
channel = grpc_ares_ev_driver_get_channel_locked(r->ev_driver);
// If dns_server is specified, use it.
if (dns_server != nullptr) {
gpr_log(GPR_INFO, "Using DNS server %s", dns_server);
GRPC_CARES_TRACE_LOG("request:%p Using DNS server %s", r, dns_server);
grpc_resolved_address addr;
if (grpc_parse_ipv4_hostport(dns_server, &addr, false /* log_errors */)) {
r->dns_server_addr.family = AF_INET;
@ -510,6 +505,28 @@ static bool resolve_as_ip_literal_locked(
return out;
}
static bool target_matches_localhost_inner(const char* name, char** host,
char** port) {
if (!gpr_split_host_port(name, host, port)) {
gpr_log(GPR_ERROR, "Unable to split host and port for name: %s", name);
return false;
}
if (gpr_stricmp(*host, "localhost") == 0) {
return true;
} else {
return false;
}
}
static bool target_matches_localhost(const char* name) {
char* host = nullptr;
char* port = nullptr;
bool out = target_matches_localhost_inner(name, &host, &port);
gpr_free(host);
gpr_free(port);
return out;
}
static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
@ -525,6 +542,10 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
r->success = false;
r->error = GRPC_ERROR_NONE;
r->pending_queries = 0;
GRPC_CARES_TRACE_LOG(
"request:%p c-ares grpc_dns_lookup_ares_locked_impl name=%s, "
"default_port=%s",
r, name, default_port);
// Early out if the target is an ipv4 or ipv6 literal.
if (resolve_as_ip_literal_locked(name, default_port, addrs)) {
GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
@ -536,6 +557,13 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
return r;
}
// Don't query for SRV and TXT records if the target is "localhost", so
// as to cut down on lookups over the network, especially in tests:
// https://github.com/grpc/proposal/pull/79
if (target_matches_localhost(name)) {
check_grpclb = false;
r->service_config_json_out = nullptr;
}
// Look up name using c-ares lib.
grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
r, dns_server, name, default_port, interested_parties, check_grpclb,

@ -110,14 +110,14 @@ static grpc_subchannel_args* get_secure_naming_subchannel_args(
grpc_channel_args* args_with_authority =
grpc_channel_args_copy_and_add(args->args, args_to_add, num_args_to_add);
grpc_uri_destroy(server_uri);
grpc_channel_security_connector* subchannel_security_connector = nullptr;
// Create the security connector using the credentials and target name.
grpc_channel_args* new_args_from_connector = nullptr;
const grpc_security_status security_status =
grpc_channel_credentials_create_security_connector(
channel_credentials, authority.get(), args_with_authority,
&subchannel_security_connector, &new_args_from_connector);
if (security_status != GRPC_SECURITY_OK) {
grpc_core::RefCountedPtr<grpc_channel_security_connector>
subchannel_security_connector =
channel_credentials->create_security_connector(
/*call_creds=*/nullptr, authority.get(), args_with_authority,
&new_args_from_connector);
if (subchannel_security_connector == nullptr) {
gpr_log(GPR_ERROR,
"Failed to create secure subchannel for secure name '%s'",
authority.get());
@ -125,15 +125,14 @@ static grpc_subchannel_args* get_secure_naming_subchannel_args(
return nullptr;
}
grpc_arg new_security_connector_arg =
grpc_security_connector_to_arg(&subchannel_security_connector->base);
grpc_security_connector_to_arg(subchannel_security_connector.get());
grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
new_args_from_connector != nullptr ? new_args_from_connector
: args_with_authority,
&new_security_connector_arg, 1);
GRPC_SECURITY_CONNECTOR_UNREF(&subchannel_security_connector->base,
"lb_channel_create");
subchannel_security_connector.reset(DEBUG_LOCATION, "lb_channel_create");
if (new_args_from_connector != nullptr) {
grpc_channel_args_destroy(new_args_from_connector);
}

@ -31,6 +31,7 @@
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/surface/api_trace.h"
@ -40,9 +41,8 @@ int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr,
grpc_server_credentials* creds) {
grpc_core::ExecCtx exec_ctx;
grpc_error* err = GRPC_ERROR_NONE;
grpc_server_security_connector* sc = nullptr;
grpc_core::RefCountedPtr<grpc_server_security_connector> sc;
int port_num = 0;
grpc_security_status status;
grpc_channel_args* args = nullptr;
GRPC_API_TRACE(
"grpc_server_add_secure_http2_port("
@ -54,30 +54,27 @@ int grpc_server_add_secure_http2_port(grpc_server* server, const char* addr,
"No credentials specified for secure server port (creds==NULL)");
goto done;
}
status = grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) {
sc = creds->create_security_connector();
if (sc == nullptr) {
char* msg;
gpr_asprintf(&msg,
"Unable to create secure server with credentials of type %s.",
creds->type);
err = grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg),
GRPC_ERROR_INT_SECURITY_STATUS, status);
creds->type());
err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
goto done;
}
// Create channel args.
grpc_arg args_to_add[2];
args_to_add[0] = grpc_server_credentials_to_arg(creds);
args_to_add[1] = grpc_security_connector_to_arg(&sc->base);
args_to_add[1] = grpc_security_connector_to_arg(sc.get());
args =
grpc_channel_args_copy_and_add(grpc_server_get_channel_args(server),
args_to_add, GPR_ARRAY_SIZE(args_to_add));
// Add server port.
err = grpc_chttp2_server_add_port(server, addr, args, &port_num);
done:
if (sc != nullptr) {
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server");
}
sc.reset(DEBUG_LOCATION, "server");
if (err != GRPC_ERROR_NONE) {
const char* msg = grpc_error_string(err);

@ -203,31 +203,34 @@ ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
ServerNode::~ServerNode() {}
char* ServerNode::RenderServerSockets(intptr_t start_socket_id) {
char* ServerNode::RenderServerSockets(intptr_t start_socket_id,
intptr_t max_results) {
// if user does not set max_results, we choose 500.
size_t pagination_limit = max_results == 0 ? 500 : max_results;
grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT);
grpc_json* json = top_level_json;
grpc_json* json_iterator = nullptr;
ChildSocketsList socket_refs;
grpc_server_populate_server_sockets(server_, &socket_refs, start_socket_id);
// declared early so it can be used outside of the loop.
size_t i = 0;
if (!socket_refs.empty()) {
// create list of socket refs
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "socketRef", nullptr, GRPC_JSON_ARRAY, false);
for (size_t i = 0; i < socket_refs.size(); ++i) {
grpc_json* socket_ref_json =
grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
for (i = 0; i < GPR_MIN(socket_refs.size(), pagination_limit); ++i) {
grpc_json* socket_ref_json = grpc_json_create_child(
nullptr, array_parent, nullptr, nullptr, GRPC_JSON_OBJECT, false);
json_iterator = grpc_json_add_number_string_child(
socket_ref_json, nullptr, "socketId", socket_refs[i]->uuid());
grpc_json_create_child(json_iterator, socket_ref_json, "name",
socket_refs[i]->remote(), GRPC_JSON_STRING, false);
}
}
// For now we do not have any pagination rules. In the future we could
// pick a constant for max_channels_sent for a GetServers request.
// Tracking: https://github.com/grpc/grpc/issues/16019.
json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
GRPC_JSON_TRUE, false);
if (i == socket_refs.size()) {
json_iterator = grpc_json_create_child(nullptr, json, "end", nullptr,
GRPC_JSON_TRUE, false);
}
char* json_str = grpc_json_dump_to_string(top_level_json, 0);
grpc_json_destroy(top_level_json);
return json_str;

@ -210,7 +210,8 @@ class ServerNode : public BaseNode {
grpc_json* RenderJson() override;
char* RenderServerSockets(intptr_t start_socket_id);
char* RenderServerSockets(intptr_t start_socket_id,
intptr_t pagination_limit);
// proxy methods to composed classes.
void AddTraceEvent(ChannelTrace::Severity severity, grpc_slice data) {

@ -252,7 +252,8 @@ char* grpc_channelz_get_server(intptr_t server_id) {
}
char* grpc_channelz_get_server_sockets(intptr_t server_id,
intptr_t start_socket_id) {
intptr_t start_socket_id,
intptr_t max_results) {
grpc_core::channelz::BaseNode* base_node =
grpc_core::channelz::ChannelzRegistry::Get(server_id);
if (base_node == nullptr ||
@ -263,7 +264,7 @@ char* grpc_channelz_get_server_sockets(intptr_t server_id,
// actually a server node
grpc_core::channelz::ServerNode* server_node =
static_cast<grpc_core::channelz::ServerNode*>(base_node);
return server_node->RenderServerSockets(start_socket_id);
return server_node->RenderServerSockets(start_socket_id, max_results);
}
char* grpc_channelz_get_channel(intptr_t channel_id) {

@ -40,15 +40,10 @@
namespace grpc_core {
// The alignment of memory returned by gpr_malloc().
constexpr size_t kAlignmentForDefaultAllocationInBytes = 8;
// Alternative to new, since we cannot use it (for fear of libstdc++)
template <typename T, typename... Args>
inline T* New(Args&&... args) {
void* p = alignof(T) > kAlignmentForDefaultAllocationInBytes
? gpr_malloc_aligned(sizeof(T), alignof(T))
: gpr_malloc(sizeof(T));
void* p = gpr_malloc(sizeof(T));
return new (p) T(std::forward<Args>(args)...);
}
@ -57,11 +52,7 @@ template <typename T>
inline void Delete(T* p) {
if (p == nullptr) return;
p->~T();
if (alignof(T) > kAlignmentForDefaultAllocationInBytes) {
gpr_free_aligned(p);
} else {
gpr_free(p);
}
gpr_free(p);
}
template <typename T>

@ -50,7 +50,7 @@ class RefCountedPtr {
}
template <typename Y>
RefCountedPtr(RefCountedPtr<Y>&& other) {
value_ = other.value_;
value_ = static_cast<T*>(other.value_);
other.value_ = nullptr;
}
@ -77,7 +77,7 @@ class RefCountedPtr {
static_assert(std::has_virtual_destructor<T>::value,
"T does not have a virtual dtor");
if (other.value_ != nullptr) other.value_->IncrementRefCount();
value_ = other.value_;
value_ = static_cast<T*>(other.value_);
}
// Copy assignment.
@ -118,7 +118,7 @@ class RefCountedPtr {
static_assert(std::has_virtual_destructor<T>::value,
"T does not have a virtual dtor");
if (value_ != nullptr) value_->Unref();
value_ = value;
value_ = static_cast<T*>(value);
}
template <typename Y>
void reset(const DebugLocation& location, const char* reason,
@ -126,7 +126,7 @@ class RefCountedPtr {
static_assert(std::has_virtual_destructor<T>::value,
"T does not have a virtual dtor");
if (value_ != nullptr) value_->Unref(location, reason);
value_ = value;
value_ = static_cast<T*>(value);
}
// TODO(roth): This method exists solely as a transition mechanism to allow

@ -29,119 +29,125 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/ssl_transport_security.h"
typedef struct {
grpc_channel_security_connector base;
tsi_ssl_client_handshaker_factory* handshaker_factory;
char* secure_peer_name;
} grpc_httpcli_ssl_channel_security_connector;
static void httpcli_ssl_destroy(grpc_security_connector* sc) {
grpc_httpcli_ssl_channel_security_connector* c =
reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
if (c->handshaker_factory != nullptr) {
tsi_ssl_client_handshaker_factory_unref(c->handshaker_factory);
c->handshaker_factory = nullptr;
class grpc_httpcli_ssl_channel_security_connector final
: public grpc_channel_security_connector {
public:
explicit grpc_httpcli_ssl_channel_security_connector(char* secure_peer_name)
: grpc_channel_security_connector(
/*url_scheme=*/nullptr,
/*channel_creds=*/nullptr,
/*request_metadata_creds=*/nullptr),
secure_peer_name_(secure_peer_name) {}
~grpc_httpcli_ssl_channel_security_connector() override {
if (handshaker_factory_ != nullptr) {
tsi_ssl_client_handshaker_factory_unref(handshaker_factory_);
}
if (secure_peer_name_ != nullptr) {
gpr_free(secure_peer_name_);
}
}
tsi_result InitHandshakerFactory(const char* pem_root_certs,
const tsi_ssl_root_certs_store* root_store) {
tsi_ssl_client_handshaker_options options;
memset(&options, 0, sizeof(options));
options.pem_root_certs = pem_root_certs;
options.root_store = root_store;
return tsi_create_ssl_client_handshaker_factory_with_options(
&options, &handshaker_factory_);
}
if (c->secure_peer_name != nullptr) gpr_free(c->secure_peer_name);
gpr_free(sc);
}
static void httpcli_ssl_add_handshakers(grpc_channel_security_connector* sc,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_httpcli_ssl_channel_security_connector* c =
reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
tsi_handshaker* handshaker = nullptr;
if (c->handshaker_factory != nullptr) {
tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
c->handshaker_factory, c->secure_peer_name, &handshaker);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) override {
tsi_handshaker* handshaker = nullptr;
if (handshaker_factory_ != nullptr) {
tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
handshaker_factory_, secure_peer_name_, &handshaker);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
}
}
grpc_handshake_manager_add(
handshake_mgr, grpc_security_handshaker_create(handshaker, this));
}
grpc_handshake_manager_add(
handshake_mgr, grpc_security_handshaker_create(handshaker, &sc->base));
}
static void httpcli_ssl_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
grpc_httpcli_ssl_channel_security_connector* c =
reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
grpc_error* error = GRPC_ERROR_NONE;
/* Check the peer name. */
if (c->secure_peer_name != nullptr &&
!tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
char* msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
c->secure_peer_name);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
tsi_ssl_client_handshaker_factory* handshaker_factory() const {
return handshaker_factory_;
}
GRPC_CLOSURE_SCHED(on_peer_checked, error);
tsi_peer_destruct(&peer);
}
static int httpcli_ssl_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_httpcli_ssl_channel_security_connector* c1 =
reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc1);
grpc_httpcli_ssl_channel_security_connector* c2 =
reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc2);
return strcmp(c1->secure_peer_name, c2->secure_peer_name);
}
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* /*auth_context*/,
grpc_closure* on_peer_checked) override {
grpc_error* error = GRPC_ERROR_NONE;
/* Check the peer name. */
if (secure_peer_name_ != nullptr &&
!tsi_ssl_peer_matches_name(&peer, secure_peer_name_)) {
char* msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
secure_peer_name_);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
}
GRPC_CLOSURE_SCHED(on_peer_checked, error);
tsi_peer_destruct(&peer);
}
static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp};
int cmp(const grpc_security_connector* other_sc) const override {
auto* other =
reinterpret_cast<const grpc_httpcli_ssl_channel_security_connector*>(
other_sc);
return strcmp(secure_peer_name_, other->secure_peer_name_);
}
static grpc_security_status httpcli_ssl_channel_security_connector_create(
const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store,
const char* secure_peer_name, grpc_channel_security_connector** sc) {
tsi_result result = TSI_OK;
grpc_httpcli_ssl_channel_security_connector* c;
bool check_call_host(const char* host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) override {
*error = GRPC_ERROR_NONE;
return true;
}
if (secure_peer_name != nullptr && pem_root_certs == nullptr) {
gpr_log(GPR_ERROR,
"Cannot assert a secure peer name without a trust root.");
return GRPC_SECURITY_ERROR;
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error* error) override {
GRPC_ERROR_UNREF(error);
}
c = static_cast<grpc_httpcli_ssl_channel_security_connector*>(
gpr_zalloc(sizeof(grpc_httpcli_ssl_channel_security_connector)));
const char* secure_peer_name() const { return secure_peer_name_; }
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &httpcli_ssl_vtable;
if (secure_peer_name != nullptr) {
c->secure_peer_name = gpr_strdup(secure_peer_name);
private:
tsi_ssl_client_handshaker_factory* handshaker_factory_ = nullptr;
char* secure_peer_name_;
};
static grpc_core::RefCountedPtr<grpc_channel_security_connector>
httpcli_ssl_channel_security_connector_create(
const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store,
const char* secure_peer_name) {
if (secure_peer_name != nullptr && pem_root_certs == nullptr) {
gpr_log(GPR_ERROR,
"Cannot assert a secure peer name without a trust root.");
return nullptr;
}
tsi_ssl_client_handshaker_options options;
memset(&options, 0, sizeof(options));
options.pem_root_certs = pem_root_certs;
options.root_store = root_store;
result = tsi_create_ssl_client_handshaker_factory_with_options(
&options, &c->handshaker_factory);
grpc_core::RefCountedPtr<grpc_httpcli_ssl_channel_security_connector> c =
grpc_core::MakeRefCounted<grpc_httpcli_ssl_channel_security_connector>(
secure_peer_name == nullptr ? nullptr : gpr_strdup(secure_peer_name));
tsi_result result = c->InitHandshakerFactory(pem_root_certs, root_store);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
httpcli_ssl_destroy(&c->base.base);
*sc = nullptr;
return GRPC_SECURITY_ERROR;
return nullptr;
}
// We don't actually need a channel credentials object in this case,
// but we set it to a non-nullptr address so that we don't trigger
// assertions in grpc_channel_security_connector_cmp().
c->base.channel_creds = (grpc_channel_credentials*)1;
c->base.add_handshakers = httpcli_ssl_add_handshakers;
*sc = &c->base;
return GRPC_SECURITY_OK;
return c;
}
/* handshaker */
@ -186,10 +192,11 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
}
c->func = on_done;
c->arg = arg;
grpc_channel_security_connector* sc = nullptr;
GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
pem_root_certs, root_store, host, &sc) == GRPC_SECURITY_OK);
grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base);
grpc_core::RefCountedPtr<grpc_channel_security_connector> sc =
httpcli_ssl_channel_security_connector_create(pem_root_certs, root_store,
host);
GPR_ASSERT(sc != nullptr);
grpc_arg channel_arg = grpc_security_connector_to_arg(sc.get());
grpc_channel_args args = {1, &channel_arg};
c->handshake_mgr = grpc_handshake_manager_create();
grpc_handshakers_add(HANDSHAKER_CLIENT, &args,
@ -197,7 +204,7 @@ static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
grpc_handshake_manager_do_handshake(
c->handshake_mgr, tcp, nullptr /* channel_args */, deadline,
nullptr /* acceptor */, on_handshake_done, c /* user_data */);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
sc.reset(DEBUG_LOCATION, "httpcli");
}
const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};

@ -70,13 +70,13 @@ typedef struct grpc_http_request {
/* A response */
typedef struct grpc_http_response {
/* HTTP status code */
int status;
int status = 0;
/* Headers: count and key/values */
size_t hdr_count;
grpc_http_header* hdrs;
size_t hdr_count = 0;
grpc_http_header* hdrs = nullptr;
/* Body: length and contents; contents are NOT null-terminated */
size_t body_length;
char* body;
size_t body_length = 0;
char* body = nullptr;
} grpc_http_response;
typedef struct {

@ -126,6 +126,7 @@ struct grpc_tcp {
int bytes_counter;
bool socket_ts_enabled; /* True if timestamping options are set on the socket
*/
bool ts_capable; /* Cache whether we can set timestamping options */
gpr_atm
stop_error_notification; /* Set to 1 if we do not want to be notified on
errors anymore */
@ -589,7 +590,7 @@ ssize_t tcp_send(int fd, const struct msghdr* msg) {
*/
static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
size_t sending_length,
ssize_t* sent_length, grpc_error** error);
ssize_t* sent_length);
/** The callback function to be invoked when we get an error on the socket. */
static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error);
@ -597,13 +598,11 @@ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error);
#ifdef GRPC_LINUX_ERRQUEUE
static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
size_t sending_length,
ssize_t* sent_length,
grpc_error** error) {
ssize_t* sent_length) {
if (!tcp->socket_ts_enabled) {
uint32_t opt = grpc_core::kTimestampingSocketOptions;
if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING,
static_cast<void*>(&opt), sizeof(opt)) != 0) {
*error = tcp_annotate_error(GRPC_OS_ERROR(errno, "setsockopt"), tcp);
grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket.");
@ -784,8 +783,7 @@ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
#else /* GRPC_LINUX_ERRQUEUE */
static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
size_t sending_length,
ssize_t* sent_length,
grpc_error** error) {
ssize_t* sent_length) {
gpr_log(GPR_ERROR, "Write with timestamps not supported for this platform");
GPR_ASSERT(0);
return false;
@ -804,7 +802,7 @@ void tcp_shutdown_buffer_list(grpc_tcp* tcp) {
gpr_mu_lock(&tcp->tb_mu);
grpc_core::TracedBuffer::Shutdown(
&tcp->tb_head, tcp->outgoing_buffer_arg,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("endpoint destroyed"));
GRPC_ERROR_CREATE_FROM_STATIC_STRING("TracedBuffer list shutdown"));
gpr_mu_unlock(&tcp->tb_mu);
tcp->outgoing_buffer_arg = nullptr;
}
@ -820,7 +818,7 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC];
msg_iovlen_type iov_size;
ssize_t sent_length;
ssize_t sent_length = 0;
size_t sending_length;
size_t trailing;
size_t unwind_slice_idx;
@ -855,13 +853,19 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
msg.msg_iov = iov;
msg.msg_iovlen = iov_size;
msg.msg_flags = 0;
bool tried_sending_message = false;
if (tcp->outgoing_buffer_arg != nullptr) {
if (!tcp_write_with_timestamps(tcp, &msg, sending_length, &sent_length,
error)) {
if (!tcp->ts_capable ||
!tcp_write_with_timestamps(tcp, &msg, sending_length, &sent_length)) {
/* We could not set socket options to collect Fathom timestamps.
* Fallback on writing without timestamps. */
tcp->ts_capable = false;
tcp_shutdown_buffer_list(tcp);
return true; /* something went wrong with timestamps */
} else {
tried_sending_message = true;
}
} else {
}
if (!tried_sending_message) {
msg.msg_control = nullptr;
msg.msg_controllen = 0;
@ -1117,6 +1121,7 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd,
tcp->is_first_read = true;
tcp->bytes_counter = -1;
tcp->socket_ts_enabled = false;
tcp->ts_capable = true;
tcp->outgoing_buffer_arg = nullptr;
/* paired with unref in grpc_tcp_destroy */
gpr_ref_init(&tcp->refcount, 1);

@ -42,7 +42,6 @@
#include "src/core/lib/iomgr/tcp_windows.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#if defined(__MSYS__) && defined(GPR_ARCH_64)
/* Nasty workaround for nasty bug when using the 64 bits msys compiler
@ -113,10 +112,7 @@ typedef struct grpc_tcp {
grpc_closure* read_cb;
grpc_closure* write_cb;
/* garbage after the last read */
grpc_slice_buffer last_read_buffer;
grpc_slice read_slice;
grpc_slice_buffer* write_slices;
grpc_slice_buffer* read_slices;
@ -135,7 +131,6 @@ static void tcp_free(grpc_tcp* tcp) {
grpc_winsocket_destroy(tcp->socket);
gpr_mu_destroy(&tcp->mu);
gpr_free(tcp->peer_string);
grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
grpc_resource_user_unref(tcp->resource_user);
if (tcp->shutting_down) GRPC_ERROR_UNREF(tcp->shutdown_error);
gpr_free(tcp);
@ -184,12 +179,9 @@ static void on_read(void* tcpp, grpc_error* error) {
grpc_tcp* tcp = (grpc_tcp*)tcpp;
grpc_closure* cb = tcp->read_cb;
grpc_winsocket* socket = tcp->socket;
grpc_slice sub;
grpc_winsocket_callback_info* info = &socket->read_info;
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "TCP:%p on_read", tcp);
}
GRPC_ERROR_REF(error);
if (error == GRPC_ERROR_NONE) {
@ -197,35 +189,13 @@ static void on_read(void* tcpp, grpc_error* error) {
char* utf8_message = gpr_format_message(info->wsa_error);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(utf8_message);
gpr_free(utf8_message);
grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
grpc_slice_unref_internal(tcp->read_slice);
} else {
if (info->bytes_transfered != 0 && !tcp->shutting_down) {
GPR_ASSERT((size_t)info->bytes_transfered <= tcp->read_slices->length);
if (static_cast<size_t>(info->bytes_transfered) !=
tcp->read_slices->length) {
grpc_slice_buffer_trim_end(
tcp->read_slices,
tcp->read_slices->length -
static_cast<size_t>(info->bytes_transfered),
&tcp->last_read_buffer);
}
GPR_ASSERT((size_t)info->bytes_transfered == tcp->read_slices->length);
if (grpc_tcp_trace.enabled()) {
size_t i;
for (i = 0; i < tcp->read_slices->count; i++) {
char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "READ %p (peer=%s): %s", tcp, tcp->peer_string,
dump);
gpr_free(dump);
}
}
sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
grpc_slice_buffer_add(tcp->read_slices, sub);
} else {
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "TCP:%p unref read_slice", tcp);
}
grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
grpc_slice_unref_internal(tcp->read_slice);
error = tcp->shutting_down
? GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"TCP stream shutting down", &tcp->shutdown_error, 1)
@ -239,8 +209,6 @@ static void on_read(void* tcpp, grpc_error* error) {
GRPC_CLOSURE_SCHED(cb, error);
}
#define DEFAULT_TARGET_READ_SIZE 8192
#define MAX_WSABUF_COUNT 16
static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
grpc_closure* cb) {
grpc_tcp* tcp = (grpc_tcp*)ep;
@ -249,12 +217,7 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
int status;
DWORD bytes_read = 0;
DWORD flags = 0;
WSABUF buffers[MAX_WSABUF_COUNT];
size_t i;
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "TCP:%p win_read", tcp);
}
WSABUF buffer;
if (tcp->shutting_down) {
GRPC_CLOSURE_SCHED(
@ -266,27 +229,18 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
tcp->read_cb = cb;
tcp->read_slices = read_slices;
grpc_slice_buffer_reset_and_unref_internal(read_slices);
grpc_slice_buffer_swap(read_slices, &tcp->last_read_buffer);
if (tcp->read_slices->length < DEFAULT_TARGET_READ_SIZE / 2 &&
tcp->read_slices->count < MAX_WSABUF_COUNT) {
// TODO(jtattermusch): slice should be allocated using resource quota
grpc_slice_buffer_add(tcp->read_slices,
GRPC_SLICE_MALLOC(DEFAULT_TARGET_READ_SIZE));
}
tcp->read_slice = GRPC_SLICE_MALLOC(8192);
GPR_ASSERT(tcp->read_slices->count <= MAX_WSABUF_COUNT);
for (i = 0; i < tcp->read_slices->count; i++) {
buffers[i].len = (ULONG)GRPC_SLICE_LENGTH(
tcp->read_slices->slices[i]); // we know slice size fits in 32bit.
buffers[i].buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[i]);
}
buffer.len = (ULONG)GRPC_SLICE_LENGTH(
tcp->read_slice); // we know slice size fits in 32bit.
buffer.buf = (char*)GRPC_SLICE_START_PTR(tcp->read_slice);
TCP_REF(tcp, "read");
/* First let's try a synchronous, non-blocking read. */
status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count,
&bytes_read, &flags, NULL, NULL);
status =
WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
/* Did we get data immediately ? Yay. */
@ -298,8 +252,8 @@ static void win_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
/* Otherwise, let's retry, by queuing a read. */
memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
status = WSARecv(tcp->socket->socket, buffers, (DWORD)tcp->read_slices->count,
&bytes_read, &flags, &info->overlapped, NULL);
status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
&info->overlapped, NULL);
if (status != 0) {
int wsa_error = WSAGetLastError();
@ -321,10 +275,6 @@ static void on_write(void* tcpp, grpc_error* error) {
grpc_winsocket_callback_info* info = &handle->write_info;
grpc_closure* cb;
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_INFO, "TCP:%p on_write", tcp);
}
GRPC_ERROR_REF(error);
gpr_mu_lock(&tcp->mu);
@ -353,21 +303,11 @@ static void win_write(grpc_endpoint* ep, grpc_slice_buffer* slices,
unsigned i;
DWORD bytes_sent;
int status;
WSABUF local_buffers[MAX_WSABUF_COUNT];
WSABUF local_buffers[16];
WSABUF* allocated = NULL;
WSABUF* buffers = local_buffers;
size_t len;
if (grpc_tcp_trace.enabled()) {
size_t i;
for (i = 0; i < slices->count; i++) {
char* data =
grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
gpr_free(data);
}
}
if (tcp->shutting_down) {
GRPC_CLOSURE_SCHED(
cb, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
@ -472,7 +412,6 @@ static void win_shutdown(grpc_endpoint* ep, grpc_error* why) {
static void win_destroy(grpc_endpoint* ep) {
grpc_network_status_unregister_endpoint(ep);
grpc_tcp* tcp = (grpc_tcp*)ep;
grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
TCP_UNREF(tcp, "destroy");
}
@ -524,7 +463,6 @@ grpc_endpoint* grpc_tcp_create(grpc_winsocket* socket,
GRPC_CLOSURE_INIT(&tcp->on_read, on_read, tcp, grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&tcp->on_write, on_write, tcp, grpc_schedule_on_exec_ctx);
tcp->peer_string = gpr_strdup(peer_string);
grpc_slice_buffer_init(&tcp->last_read_buffer);
tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
/* Tell network status tracking code about the new endpoint */
grpc_network_status_register_endpoint(&tcp->base);

@ -23,6 +23,8 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/arena.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@ -50,13 +52,11 @@ grpc_call_error grpc_call_set_credentials(grpc_call* call,
ctx = static_cast<grpc_client_security_context*>(
grpc_call_context_get(call, GRPC_CONTEXT_SECURITY));
if (ctx == nullptr) {
ctx = grpc_client_security_context_create(grpc_call_get_arena(call));
ctx->creds = grpc_call_credentials_ref(creds);
ctx = grpc_client_security_context_create(grpc_call_get_arena(call), creds);
grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx,
grpc_client_security_context_destroy);
} else {
grpc_call_credentials_unref(ctx->creds);
ctx->creds = grpc_call_credentials_ref(creds);
ctx->creds = creds != nullptr ? creds->Ref() : nullptr;
}
return GRPC_CALL_OK;
@ -66,33 +66,45 @@ grpc_auth_context* grpc_call_auth_context(grpc_call* call) {
void* sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call));
if (sec_ctx == nullptr) return nullptr;
return grpc_call_is_client(call)
? GRPC_AUTH_CONTEXT_REF(
((grpc_client_security_context*)sec_ctx)->auth_context,
"grpc_call_auth_context client")
: GRPC_AUTH_CONTEXT_REF(
((grpc_server_security_context*)sec_ctx)->auth_context,
"grpc_call_auth_context server");
if (grpc_call_is_client(call)) {
auto* sc = static_cast<grpc_client_security_context*>(sec_ctx);
if (sc->auth_context == nullptr) {
return nullptr;
} else {
return sc->auth_context
->Ref(DEBUG_LOCATION, "grpc_call_auth_context client")
.release();
}
} else {
auto* sc = static_cast<grpc_server_security_context*>(sec_ctx);
if (sc->auth_context == nullptr) {
return nullptr;
} else {
return sc->auth_context
->Ref(DEBUG_LOCATION, "grpc_call_auth_context server")
.release();
}
}
}
void grpc_auth_context_release(grpc_auth_context* context) {
GRPC_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context));
GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref");
if (context == nullptr) return;
context->Unref(DEBUG_LOCATION, "grpc_auth_context_unref");
}
/* --- grpc_client_security_context --- */
grpc_client_security_context::~grpc_client_security_context() {
grpc_call_credentials_unref(creds);
GRPC_AUTH_CONTEXT_UNREF(auth_context, "client_security_context");
auth_context.reset(DEBUG_LOCATION, "client_security_context");
if (extension.instance != nullptr && extension.destroy != nullptr) {
extension.destroy(extension.instance);
}
}
grpc_client_security_context* grpc_client_security_context_create(
gpr_arena* arena) {
gpr_arena* arena, grpc_call_credentials* creds) {
return new (gpr_arena_alloc(arena, sizeof(grpc_client_security_context)))
grpc_client_security_context();
grpc_client_security_context(creds != nullptr ? creds->Ref() : nullptr);
}
void grpc_client_security_context_destroy(void* ctx) {
@ -104,7 +116,7 @@ void grpc_client_security_context_destroy(void* ctx) {
/* --- grpc_server_security_context --- */
grpc_server_security_context::~grpc_server_security_context() {
GRPC_AUTH_CONTEXT_UNREF(auth_context, "server_security_context");
auth_context.reset(DEBUG_LOCATION, "server_security_context");
if (extension.instance != nullptr && extension.destroy != nullptr) {
extension.destroy(extension.instance);
}
@ -126,69 +138,11 @@ void grpc_server_security_context_destroy(void* ctx) {
static grpc_auth_property_iterator empty_iterator = {nullptr, 0, nullptr};
grpc_auth_context* grpc_auth_context_create(grpc_auth_context* chained) {
grpc_auth_context* ctx =
static_cast<grpc_auth_context*>(gpr_zalloc(sizeof(grpc_auth_context)));
gpr_ref_init(&ctx->refcount, 1);
if (chained != nullptr) {
ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
ctx->peer_identity_property_name =
ctx->chained->peer_identity_property_name;
}
return ctx;
}
#ifndef NDEBUG
grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* ctx,
const char* file, int line,
const char* reason) {
if (ctx == nullptr) return nullptr;
if (grpc_trace_auth_context_refcount.enabled()) {
gpr_atm val = gpr_atm_no_barrier_load(&ctx->refcount.count);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"AUTH_CONTEXT:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", ctx, val,
val + 1, reason);
}
#else
grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* ctx) {
if (ctx == nullptr) return nullptr;
#endif
gpr_ref(&ctx->refcount);
return ctx;
}
#ifndef NDEBUG
void grpc_auth_context_unref(grpc_auth_context* ctx, const char* file, int line,
const char* reason) {
if (ctx == nullptr) return;
if (grpc_trace_auth_context_refcount.enabled()) {
gpr_atm val = gpr_atm_no_barrier_load(&ctx->refcount.count);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"AUTH_CONTEXT:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", ctx, val,
val - 1, reason);
}
#else
void grpc_auth_context_unref(grpc_auth_context* ctx) {
if (ctx == nullptr) return;
#endif
if (gpr_unref(&ctx->refcount)) {
size_t i;
GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained");
if (ctx->properties.array != nullptr) {
for (i = 0; i < ctx->properties.count; i++) {
grpc_auth_property_reset(&ctx->properties.array[i]);
}
gpr_free(ctx->properties.array);
}
gpr_free(ctx);
}
}
const char* grpc_auth_context_peer_identity_property_name(
const grpc_auth_context* ctx) {
GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1,
(ctx));
return ctx->peer_identity_property_name;
return ctx->peer_identity_property_name();
}
int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context* ctx,
@ -204,13 +158,13 @@ int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context* ctx,
name != nullptr ? name : "NULL");
return 0;
}
ctx->peer_identity_property_name = prop->name;
ctx->set_peer_identity_property_name(prop->name);
return 1;
}
int grpc_auth_context_peer_is_authenticated(const grpc_auth_context* ctx) {
GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx));
return ctx->peer_identity_property_name == nullptr ? 0 : 1;
return ctx->is_authenticated();
}
grpc_auth_property_iterator grpc_auth_context_property_iterator(
@ -226,16 +180,17 @@ const grpc_auth_property* grpc_auth_property_iterator_next(
grpc_auth_property_iterator* it) {
GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it));
if (it == nullptr || it->ctx == nullptr) return nullptr;
while (it->index == it->ctx->properties.count) {
if (it->ctx->chained == nullptr) return nullptr;
it->ctx = it->ctx->chained;
while (it->index == it->ctx->properties().count) {
if (it->ctx->chained() == nullptr) return nullptr;
it->ctx = it->ctx->chained();
it->index = 0;
}
if (it->name == nullptr) {
return &it->ctx->properties.array[it->index++];
return &it->ctx->properties().array[it->index++];
} else {
while (it->index < it->ctx->properties.count) {
const grpc_auth_property* prop = &it->ctx->properties.array[it->index++];
while (it->index < it->ctx->properties().count) {
const grpc_auth_property* prop =
&it->ctx->properties().array[it->index++];
GPR_ASSERT(prop->name != nullptr);
if (strcmp(it->name, prop->name) == 0) {
return prop;
@ -262,49 +217,56 @@ grpc_auth_property_iterator grpc_auth_context_peer_identity(
GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx));
if (ctx == nullptr) return empty_iterator;
return grpc_auth_context_find_properties_by_name(
ctx, ctx->peer_identity_property_name);
ctx, ctx->peer_identity_property_name());
}
static void ensure_auth_context_capacity(grpc_auth_context* ctx) {
if (ctx->properties.count == ctx->properties.capacity) {
ctx->properties.capacity =
GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2);
ctx->properties.array = static_cast<grpc_auth_property*>(
gpr_realloc(ctx->properties.array,
ctx->properties.capacity * sizeof(grpc_auth_property)));
void grpc_auth_context::ensure_capacity() {
if (properties_.count == properties_.capacity) {
properties_.capacity =
GPR_MAX(properties_.capacity + 8, properties_.capacity * 2);
properties_.array = static_cast<grpc_auth_property*>(gpr_realloc(
properties_.array, properties_.capacity * sizeof(grpc_auth_property)));
}
}
void grpc_auth_context::add_property(const char* name, const char* value,
size_t value_length) {
ensure_capacity();
grpc_auth_property* prop = &properties_.array[properties_.count++];
prop->name = gpr_strdup(name);
prop->value = static_cast<char*>(gpr_malloc(value_length + 1));
memcpy(prop->value, value, value_length);
prop->value[value_length] = '\0';
prop->value_length = value_length;
}
void grpc_auth_context_add_property(grpc_auth_context* ctx, const char* name,
const char* value, size_t value_length) {
grpc_auth_property* prop;
GRPC_API_TRACE(
"grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, "
"value_length=%lu)",
6,
(ctx, name, (int)value_length, (int)value_length, value,
(unsigned long)value_length));
ensure_auth_context_capacity(ctx);
prop = &ctx->properties.array[ctx->properties.count++];
ctx->add_property(name, value, value_length);
}
void grpc_auth_context::add_cstring_property(const char* name,
const char* value) {
ensure_capacity();
grpc_auth_property* prop = &properties_.array[properties_.count++];
prop->name = gpr_strdup(name);
prop->value = static_cast<char*>(gpr_malloc(value_length + 1));
memcpy(prop->value, value, value_length);
prop->value[value_length] = '\0';
prop->value_length = value_length;
prop->value = gpr_strdup(value);
prop->value_length = strlen(value);
}
void grpc_auth_context_add_cstring_property(grpc_auth_context* ctx,
const char* name,
const char* value) {
grpc_auth_property* prop;
GRPC_API_TRACE(
"grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3,
(ctx, name, value));
ensure_auth_context_capacity(ctx);
prop = &ctx->properties.array[ctx->properties.count++];
prop->name = gpr_strdup(name);
prop->value = gpr_strdup(value);
prop->value_length = strlen(value);
ctx->add_cstring_property(name, value);
}
void grpc_auth_property_reset(grpc_auth_property* property) {
@ -314,12 +276,17 @@ void grpc_auth_property_reset(grpc_auth_property* property) {
}
static void auth_context_pointer_arg_destroy(void* p) {
GRPC_AUTH_CONTEXT_UNREF((grpc_auth_context*)p, "auth_context_pointer_arg");
if (p != nullptr) {
static_cast<grpc_auth_context*>(p)->Unref(DEBUG_LOCATION,
"auth_context_pointer_arg");
}
}
static void* auth_context_pointer_arg_copy(void* p) {
return GRPC_AUTH_CONTEXT_REF((grpc_auth_context*)p,
"auth_context_pointer_arg");
auto* ctx = static_cast<grpc_auth_context*>(p);
return ctx == nullptr
? nullptr
: ctx->Ref(DEBUG_LOCATION, "auth_context_pointer_arg").release();
}
static int auth_context_pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }

@ -21,6 +21,8 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/security/credentials/credentials.h"
@ -40,39 +42,59 @@ struct grpc_auth_property_array {
size_t capacity = 0;
};
struct grpc_auth_context {
grpc_auth_context() { gpr_ref_init(&refcount, 0); }
void grpc_auth_property_reset(grpc_auth_property* property);
struct grpc_auth_context* chained = nullptr;
grpc_auth_property_array properties;
gpr_refcount refcount;
const char* peer_identity_property_name = nullptr;
grpc_pollset* pollset = nullptr;
// This type is forward declared as a C struct and we cannot define it as a
// class. Otherwise, compiler will complain about type mismatch due to
// -Wmismatched-tags.
struct grpc_auth_context
: public grpc_core::RefCounted<grpc_auth_context,
grpc_core::NonPolymorphicRefCount> {
public:
explicit grpc_auth_context(
grpc_core::RefCountedPtr<grpc_auth_context> chained)
: grpc_core::RefCounted<grpc_auth_context,
grpc_core::NonPolymorphicRefCount>(
&grpc_trace_auth_context_refcount),
chained_(std::move(chained)) {
if (chained_ != nullptr) {
peer_identity_property_name_ = chained_->peer_identity_property_name_;
}
}
~grpc_auth_context() {
chained_.reset(DEBUG_LOCATION, "chained");
if (properties_.array != nullptr) {
for (size_t i = 0; i < properties_.count; i++) {
grpc_auth_property_reset(&properties_.array[i]);
}
gpr_free(properties_.array);
}
}
const grpc_auth_context* chained() const { return chained_.get(); }
const grpc_auth_property_array& properties() const { return properties_; }
bool is_authenticated() const {
return peer_identity_property_name_ != nullptr;
}
const char* peer_identity_property_name() const {
return peer_identity_property_name_;
}
void set_peer_identity_property_name(const char* name) {
peer_identity_property_name_ = name;
}
void ensure_capacity();
void add_property(const char* name, const char* value, size_t value_length);
void add_cstring_property(const char* name, const char* value);
private:
grpc_core::RefCountedPtr<grpc_auth_context> chained_;
grpc_auth_property_array properties_;
const char* peer_identity_property_name_ = nullptr;
};
/* Creation. */
grpc_auth_context* grpc_auth_context_create(grpc_auth_context* chained);
/* Refcounting. */
#ifndef NDEBUG
#define GRPC_AUTH_CONTEXT_REF(p, r) \
grpc_auth_context_ref((p), __FILE__, __LINE__, (r))
#define GRPC_AUTH_CONTEXT_UNREF(p, r) \
grpc_auth_context_unref((p), __FILE__, __LINE__, (r))
grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* policy,
const char* file, int line,
const char* reason);
void grpc_auth_context_unref(grpc_auth_context* policy, const char* file,
int line, const char* reason);
#else
#define GRPC_AUTH_CONTEXT_REF(p, r) grpc_auth_context_ref((p))
#define GRPC_AUTH_CONTEXT_UNREF(p, r) grpc_auth_context_unref((p))
grpc_auth_context* grpc_auth_context_ref(grpc_auth_context* policy);
void grpc_auth_context_unref(grpc_auth_context* policy);
#endif
void grpc_auth_property_reset(grpc_auth_property* property);
/* --- grpc_security_context_extension ---
Extension to the security context that may be set in a filter and accessed
@ -88,16 +110,18 @@ struct grpc_security_context_extension {
Internal client-side security context. */
struct grpc_client_security_context {
grpc_client_security_context() = default;
explicit grpc_client_security_context(
grpc_core::RefCountedPtr<grpc_call_credentials> creds)
: creds(std::move(creds)) {}
~grpc_client_security_context();
grpc_call_credentials* creds = nullptr;
grpc_auth_context* auth_context = nullptr;
grpc_core::RefCountedPtr<grpc_call_credentials> creds;
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
grpc_security_context_extension extension;
};
grpc_client_security_context* grpc_client_security_context_create(
gpr_arena* arena);
gpr_arena* arena, grpc_call_credentials* creds);
void grpc_client_security_context_destroy(void* ctx);
/* --- grpc_server_security_context ---
@ -108,7 +132,7 @@ struct grpc_server_security_context {
grpc_server_security_context() = default;
~grpc_server_security_context();
grpc_auth_context* auth_context = nullptr;
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
grpc_security_context_extension extension;
};

@ -33,40 +33,47 @@
#define GRPC_CREDENTIALS_TYPE_ALTS "Alts"
#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080"
static void alts_credentials_destruct(grpc_channel_credentials* creds) {
grpc_alts_credentials* alts_creds =
reinterpret_cast<grpc_alts_credentials*>(creds);
grpc_alts_credentials_options_destroy(alts_creds->options);
gpr_free(alts_creds->handshaker_service_url);
}
static void alts_server_credentials_destruct(grpc_server_credentials* creds) {
grpc_alts_server_credentials* alts_creds =
reinterpret_cast<grpc_alts_server_credentials*>(creds);
grpc_alts_credentials_options_destroy(alts_creds->options);
gpr_free(alts_creds->handshaker_service_url);
grpc_alts_credentials::grpc_alts_credentials(
const grpc_alts_credentials_options* options,
const char* handshaker_service_url)
: grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_ALTS),
options_(grpc_alts_credentials_options_copy(options)),
handshaker_service_url_(handshaker_service_url == nullptr
? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
: gpr_strdup(handshaker_service_url)) {}
grpc_alts_credentials::~grpc_alts_credentials() {
grpc_alts_credentials_options_destroy(options_);
gpr_free(handshaker_service_url_);
}
static grpc_security_status alts_create_security_connector(
grpc_channel_credentials* creds,
grpc_call_credentials* request_metadata_creds, const char* target_name,
const grpc_channel_args* args, grpc_channel_security_connector** sc,
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_alts_credentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target_name, const grpc_channel_args* args,
grpc_channel_args** new_args) {
return grpc_alts_channel_security_connector_create(
creds, request_metadata_creds, target_name, sc);
this->Ref(), std::move(call_creds), target_name);
}
static grpc_security_status alts_server_create_security_connector(
grpc_server_credentials* creds, grpc_server_security_connector** sc) {
return grpc_alts_server_security_connector_create(creds, sc);
grpc_alts_server_credentials::grpc_alts_server_credentials(
const grpc_alts_credentials_options* options,
const char* handshaker_service_url)
: grpc_server_credentials(GRPC_CREDENTIALS_TYPE_ALTS),
options_(grpc_alts_credentials_options_copy(options)),
handshaker_service_url_(handshaker_service_url == nullptr
? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
: gpr_strdup(handshaker_service_url)) {}
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_credentials::create_security_connector() {
return grpc_alts_server_security_connector_create(this->Ref());
}
static const grpc_channel_credentials_vtable alts_credentials_vtable = {
alts_credentials_destruct, alts_create_security_connector,
/*duplicate_without_call_credentials=*/nullptr};
static const grpc_server_credentials_vtable alts_server_credentials_vtable = {
alts_server_credentials_destruct, alts_server_create_security_connector};
grpc_alts_server_credentials::~grpc_alts_server_credentials() {
grpc_alts_credentials_options_destroy(options_);
gpr_free(handshaker_service_url_);
}
grpc_channel_credentials* grpc_alts_credentials_create_customized(
const grpc_alts_credentials_options* options,
@ -74,17 +81,7 @@ grpc_channel_credentials* grpc_alts_credentials_create_customized(
if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) {
return nullptr;
}
auto creds = static_cast<grpc_alts_credentials*>(
gpr_zalloc(sizeof(grpc_alts_credentials)));
creds->options = grpc_alts_credentials_options_copy(options);
creds->handshaker_service_url =
handshaker_service_url == nullptr
? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
: gpr_strdup(handshaker_service_url);
creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS;
creds->base.vtable = &alts_credentials_vtable;
gpr_ref_init(&creds->base.refcount, 1);
return &creds->base;
return grpc_core::New<grpc_alts_credentials>(options, handshaker_service_url);
}
grpc_server_credentials* grpc_alts_server_credentials_create_customized(
@ -93,17 +90,8 @@ grpc_server_credentials* grpc_alts_server_credentials_create_customized(
if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) {
return nullptr;
}
auto creds = static_cast<grpc_alts_server_credentials*>(
gpr_zalloc(sizeof(grpc_alts_server_credentials)));
creds->options = grpc_alts_credentials_options_copy(options);
creds->handshaker_service_url =
handshaker_service_url == nullptr
? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
: gpr_strdup(handshaker_service_url);
creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS;
creds->base.vtable = &alts_server_credentials_vtable;
gpr_ref_init(&creds->base.refcount, 1);
return &creds->base;
return grpc_core::New<grpc_alts_server_credentials>(options,
handshaker_service_url);
}
grpc_channel_credentials* grpc_alts_credentials_create(

@ -27,18 +27,45 @@
#include "src/core/lib/security/credentials/credentials.h"
/* Main struct for grpc ALTS channel credential. */
typedef struct grpc_alts_credentials {
grpc_channel_credentials base;
grpc_alts_credentials_options* options;
char* handshaker_service_url;
} grpc_alts_credentials;
class grpc_alts_credentials final : public grpc_channel_credentials {
public:
grpc_alts_credentials(const grpc_alts_credentials_options* options,
const char* handshaker_service_url);
~grpc_alts_credentials() override;
grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target_name, const grpc_channel_args* args,
grpc_channel_args** new_args) override;
const grpc_alts_credentials_options* options() const { return options_; }
grpc_alts_credentials_options* mutable_options() { return options_; }
const char* handshaker_service_url() const { return handshaker_service_url_; }
private:
grpc_alts_credentials_options* options_;
char* handshaker_service_url_;
};
/* Main struct for grpc ALTS server credential. */
typedef struct grpc_alts_server_credentials {
grpc_server_credentials base;
grpc_alts_credentials_options* options;
char* handshaker_service_url;
} grpc_alts_server_credentials;
class grpc_alts_server_credentials final : public grpc_server_credentials {
public:
grpc_alts_server_credentials(const grpc_alts_credentials_options* options,
const char* handshaker_service_url);
~grpc_alts_server_credentials() override;
grpc_core::RefCountedPtr<grpc_server_security_connector>
create_security_connector() override;
const grpc_alts_credentials_options* options() const { return options_; }
grpc_alts_credentials_options* mutable_options() { return options_; }
const char* handshaker_service_url() const { return handshaker_service_url_; }
private:
grpc_alts_credentials_options* options_;
char* handshaker_service_url_;
};
/**
* This method creates an ALTS channel credential object with customized

@ -20,8 +20,10 @@
#include "src/core/lib/security/credentials/composite/composite_credentials.h"
#include <string.h>
#include <cstring>
#include <new>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/surface/api_trace.h"
@ -31,36 +33,83 @@
/* -- Composite call credentials. -- */
typedef struct {
static void composite_call_metadata_cb(void* arg, grpc_error* error);
grpc_call_credentials_array::~grpc_call_credentials_array() {
for (size_t i = 0; i < num_creds_; ++i) {
creds_array_[i].~RefCountedPtr<grpc_call_credentials>();
}
if (creds_array_ != nullptr) {
gpr_free(creds_array_);
}
}
grpc_call_credentials_array::grpc_call_credentials_array(
const grpc_call_credentials_array& that)
: num_creds_(that.num_creds_) {
reserve(that.capacity_);
for (size_t i = 0; i < num_creds_; ++i) {
new (&creds_array_[i])
grpc_core::RefCountedPtr<grpc_call_credentials>(that.creds_array_[i]);
}
}
void grpc_call_credentials_array::reserve(size_t capacity) {
if (capacity_ >= capacity) {
return;
}
grpc_core::RefCountedPtr<grpc_call_credentials>* new_arr =
static_cast<grpc_core::RefCountedPtr<grpc_call_credentials>*>(gpr_malloc(
sizeof(grpc_core::RefCountedPtr<grpc_call_credentials>) * capacity));
if (creds_array_ != nullptr) {
for (size_t i = 0; i < num_creds_; ++i) {
new (&new_arr[i]) grpc_core::RefCountedPtr<grpc_call_credentials>(
std::move(creds_array_[i]));
creds_array_[i].~RefCountedPtr<grpc_call_credentials>();
}
gpr_free(creds_array_);
}
creds_array_ = new_arr;
capacity_ = capacity;
}
namespace {
struct grpc_composite_call_credentials_metadata_context {
grpc_composite_call_credentials_metadata_context(
grpc_composite_call_credentials* composite_creds,
grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata)
: composite_creds(composite_creds),
pollent(pollent),
auth_md_context(auth_md_context),
md_array(md_array),
on_request_metadata(on_request_metadata) {
GRPC_CLOSURE_INIT(&internal_on_request_metadata, composite_call_metadata_cb,
this, grpc_schedule_on_exec_ctx);
}
grpc_composite_call_credentials* composite_creds;
size_t creds_index;
size_t creds_index = 0;
grpc_polling_entity* pollent;
grpc_auth_metadata_context auth_md_context;
grpc_credentials_mdelem_array* md_array;
grpc_closure* on_request_metadata;
grpc_closure internal_on_request_metadata;
} grpc_composite_call_credentials_metadata_context;
static void composite_call_destruct(grpc_call_credentials* creds) {
grpc_composite_call_credentials* c =
reinterpret_cast<grpc_composite_call_credentials*>(creds);
for (size_t i = 0; i < c->inner.num_creds; i++) {
grpc_call_credentials_unref(c->inner.creds_array[i]);
}
gpr_free(c->inner.creds_array);
}
};
} // namespace
static void composite_call_metadata_cb(void* arg, grpc_error* error) {
grpc_composite_call_credentials_metadata_context* ctx =
static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
if (error == GRPC_ERROR_NONE) {
const grpc_call_credentials_array& inner = ctx->composite_creds->inner();
/* See if we need to get some more metadata. */
if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
grpc_call_credentials* inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
if (grpc_call_credentials_get_request_metadata(
inner_creds, ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, &error)) {
if (ctx->creds_index < inner.size()) {
if (inner.get(ctx->creds_index++)
->get_request_metadata(
ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, &error)) {
// Synchronous response, so call ourselves recursively.
composite_call_metadata_cb(arg, error);
GRPC_ERROR_UNREF(error);
@ -73,76 +122,86 @@ static void composite_call_metadata_cb(void* arg, grpc_error* error) {
gpr_free(ctx);
}
static bool composite_call_get_request_metadata(
grpc_call_credentials* creds, grpc_polling_entity* pollent,
grpc_auth_metadata_context auth_md_context,
bool grpc_composite_call_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_composite_call_credentials* c =
reinterpret_cast<grpc_composite_call_credentials*>(creds);
grpc_composite_call_credentials_metadata_context* ctx;
ctx = static_cast<grpc_composite_call_credentials_metadata_context*>(
gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context)));
ctx->composite_creds = c;
ctx->pollent = pollent;
ctx->auth_md_context = auth_md_context;
ctx->md_array = md_array;
ctx->on_request_metadata = on_request_metadata;
GRPC_CLOSURE_INIT(&ctx->internal_on_request_metadata,
composite_call_metadata_cb, ctx, grpc_schedule_on_exec_ctx);
ctx = grpc_core::New<grpc_composite_call_credentials_metadata_context>(
this, pollent, auth_md_context, md_array, on_request_metadata);
bool synchronous = true;
while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
grpc_call_credentials* inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
if (grpc_call_credentials_get_request_metadata(
inner_creds, ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, error)) {
const grpc_call_credentials_array& inner = ctx->composite_creds->inner();
while (ctx->creds_index < inner.size()) {
if (inner.get(ctx->creds_index++)
->get_request_metadata(ctx->pollent, ctx->auth_md_context,
ctx->md_array,
&ctx->internal_on_request_metadata, error)) {
if (*error != GRPC_ERROR_NONE) break;
} else {
synchronous = false; // Async return.
break;
}
}
if (synchronous) gpr_free(ctx);
if (synchronous) grpc_core::Delete(ctx);
return synchronous;
}
static void composite_call_cancel_get_request_metadata(
grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
grpc_composite_call_credentials* c =
reinterpret_cast<grpc_composite_call_credentials*>(creds);
for (size_t i = 0; i < c->inner.num_creds; ++i) {
grpc_call_credentials_cancel_get_request_metadata(
c->inner.creds_array[i], md_array, GRPC_ERROR_REF(error));
void grpc_composite_call_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
for (size_t i = 0; i < inner_.size(); ++i) {
inner_.get(i)->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
static grpc_call_credentials_vtable composite_call_credentials_vtable = {
composite_call_destruct, composite_call_get_request_metadata,
composite_call_cancel_get_request_metadata};
static size_t get_creds_array_size(const grpc_call_credentials* creds,
bool is_composite) {
return is_composite
? static_cast<const grpc_composite_call_credentials*>(creds)
->inner()
.size()
: 1;
}
static grpc_call_credentials_array get_creds_array(
grpc_call_credentials** creds_addr) {
grpc_call_credentials_array result;
grpc_call_credentials* creds = *creds_addr;
result.creds_array = creds_addr;
result.num_creds = 1;
if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
result = *grpc_composite_call_credentials_get_credentials(creds);
void grpc_composite_call_credentials::push_to_inner(
grpc_core::RefCountedPtr<grpc_call_credentials> creds, bool is_composite) {
if (!is_composite) {
inner_.push_back(std::move(creds));
return;
}
return result;
auto composite_creds =
static_cast<grpc_composite_call_credentials*>(creds.get());
for (size_t i = 0; i < composite_creds->inner().size(); ++i) {
inner_.push_back(std::move(composite_creds->inner_.get_mutable(i)));
}
}
grpc_composite_call_credentials::grpc_composite_call_credentials(
grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
grpc_core::RefCountedPtr<grpc_call_credentials> creds2)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) {
const bool creds1_is_composite =
strcmp(creds1->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
const bool creds2_is_composite =
strcmp(creds2->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
const size_t size = get_creds_array_size(creds1.get(), creds1_is_composite) +
get_creds_array_size(creds2.get(), creds2_is_composite);
inner_.reserve(size);
push_to_inner(std::move(creds1), creds1_is_composite);
push_to_inner(std::move(creds2), creds2_is_composite);
}
static grpc_core::RefCountedPtr<grpc_call_credentials>
composite_call_credentials_create(
grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
grpc_core::RefCountedPtr<grpc_call_credentials> creds2) {
return grpc_core::MakeRefCounted<grpc_composite_call_credentials>(
std::move(creds1), std::move(creds2));
}
grpc_call_credentials* grpc_composite_call_credentials_create(
grpc_call_credentials* creds1, grpc_call_credentials* creds2,
void* reserved) {
size_t i;
size_t creds_array_byte_size;
grpc_call_credentials_array creds1_array;
grpc_call_credentials_array creds2_array;
grpc_composite_call_credentials* c;
GRPC_API_TRACE(
"grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
"reserved=%p)",
@ -150,120 +209,40 @@ grpc_call_credentials* grpc_composite_call_credentials_create(
GPR_ASSERT(reserved == nullptr);
GPR_ASSERT(creds1 != nullptr);
GPR_ASSERT(creds2 != nullptr);
c = static_cast<grpc_composite_call_credentials*>(
gpr_zalloc(sizeof(grpc_composite_call_credentials)));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
c->base.vtable = &composite_call_credentials_vtable;
gpr_ref_init(&c->base.refcount, 1);
creds1_array = get_creds_array(&creds1);
creds2_array = get_creds_array(&creds2);
c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials*);
c->inner.creds_array =
static_cast<grpc_call_credentials**>(gpr_zalloc(creds_array_byte_size));
for (i = 0; i < creds1_array.num_creds; i++) {
grpc_call_credentials* cur_creds = creds1_array.creds_array[i];
c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
}
for (i = 0; i < creds2_array.num_creds; i++) {
grpc_call_credentials* cur_creds = creds2_array.creds_array[i];
c->inner.creds_array[i + creds1_array.num_creds] =
grpc_call_credentials_ref(cur_creds);
}
return &c->base;
}
const grpc_call_credentials_array*
grpc_composite_call_credentials_get_credentials(grpc_call_credentials* creds) {
const grpc_composite_call_credentials* c =
reinterpret_cast<const grpc_composite_call_credentials*>(creds);
GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
return &c->inner;
}
grpc_call_credentials* grpc_credentials_contains_type(
grpc_call_credentials* creds, const char* type,
grpc_call_credentials** composite_creds) {
size_t i;
if (strcmp(creds->type, type) == 0) {
if (composite_creds != nullptr) *composite_creds = nullptr;
return creds;
} else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
const grpc_call_credentials_array* inner_creds_array =
grpc_composite_call_credentials_get_credentials(creds);
for (i = 0; i < inner_creds_array->num_creds; i++) {
if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
if (composite_creds != nullptr) *composite_creds = creds;
return inner_creds_array->creds_array[i];
}
}
}
return nullptr;
return composite_call_credentials_create(creds1->Ref(), creds2->Ref())
.release();
}
/* -- Composite channel credentials. -- */
static void composite_channel_destruct(grpc_channel_credentials* creds) {
grpc_composite_channel_credentials* c =
reinterpret_cast<grpc_composite_channel_credentials*>(creds);
grpc_channel_credentials_unref(c->inner_creds);
grpc_call_credentials_unref(c->call_creds);
}
static grpc_security_status composite_channel_create_security_connector(
grpc_channel_credentials* creds, grpc_call_credentials* call_creds,
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_composite_channel_credentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
grpc_composite_channel_credentials* c =
reinterpret_cast<grpc_composite_channel_credentials*>(creds);
grpc_security_status status = GRPC_SECURITY_ERROR;
GPR_ASSERT(c->inner_creds != nullptr && c->call_creds != nullptr &&
c->inner_creds->vtable != nullptr &&
c->inner_creds->vtable->create_security_connector != nullptr);
grpc_channel_args** new_args) {
GPR_ASSERT(inner_creds_ != nullptr && call_creds_ != nullptr);
/* If we are passed a call_creds, create a call composite to pass it
downstream. */
if (call_creds != nullptr) {
grpc_call_credentials* composite_call_creds =
grpc_composite_call_credentials_create(c->call_creds, call_creds,
nullptr);
status = c->inner_creds->vtable->create_security_connector(
c->inner_creds, composite_call_creds, target, args, sc, new_args);
grpc_call_credentials_unref(composite_call_creds);
return inner_creds_->create_security_connector(
composite_call_credentials_create(call_creds_, std::move(call_creds)),
target, args, new_args);
} else {
status = c->inner_creds->vtable->create_security_connector(
c->inner_creds, c->call_creds, target, args, sc, new_args);
return inner_creds_->create_security_connector(call_creds_, target, args,
new_args);
}
return status;
}
static grpc_channel_credentials*
composite_channel_duplicate_without_call_credentials(
grpc_channel_credentials* creds) {
grpc_composite_channel_credentials* c =
reinterpret_cast<grpc_composite_channel_credentials*>(creds);
return grpc_channel_credentials_ref(c->inner_creds);
}
static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
composite_channel_destruct, composite_channel_create_security_connector,
composite_channel_duplicate_without_call_credentials};
grpc_channel_credentials* grpc_composite_channel_credentials_create(
grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
void* reserved) {
grpc_composite_channel_credentials* c =
static_cast<grpc_composite_channel_credentials*>(gpr_zalloc(sizeof(*c)));
GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr &&
reserved == nullptr);
GRPC_API_TRACE(
"grpc_composite_channel_credentials_create(channel_creds=%p, "
"call_creds=%p, reserved=%p)",
3, (channel_creds, call_creds, reserved));
c->base.type = channel_creds->type;
c->base.vtable = &composite_channel_credentials_vtable;
gpr_ref_init(&c->base.refcount, 1);
c->inner_creds = grpc_channel_credentials_ref(channel_creds);
c->call_creds = grpc_call_credentials_ref(call_creds);
return &c->base;
return grpc_core::New<grpc_composite_channel_credentials>(
channel_creds->Ref(), call_creds->Ref());
}

@ -21,39 +21,104 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/credentials/credentials.h"
typedef struct {
grpc_call_credentials** creds_array;
size_t num_creds;
} grpc_call_credentials_array;
// TODO(soheil): Replace this with InlinedVector once #16032 is resolved.
class grpc_call_credentials_array {
public:
grpc_call_credentials_array() = default;
grpc_call_credentials_array(const grpc_call_credentials_array& that);
const grpc_call_credentials_array*
grpc_composite_call_credentials_get_credentials(
grpc_call_credentials* composite_creds);
~grpc_call_credentials_array();
/* Returns creds if creds is of the specified type or the inner creds of the
specified type (if found), if the creds is of type COMPOSITE.
If composite_creds is not NULL, *composite_creds will point to creds if of
type COMPOSITE in case of success. */
grpc_call_credentials* grpc_credentials_contains_type(
grpc_call_credentials* creds, const char* type,
grpc_call_credentials** composite_creds);
void reserve(size_t capacity);
// Must reserve before pushing any data.
void push_back(grpc_core::RefCountedPtr<grpc_call_credentials> cred) {
GPR_DEBUG_ASSERT(capacity_ > num_creds_);
new (&creds_array_[num_creds_++])
grpc_core::RefCountedPtr<grpc_call_credentials>(std::move(cred));
}
const grpc_core::RefCountedPtr<grpc_call_credentials>& get(size_t i) const {
GPR_DEBUG_ASSERT(i < num_creds_);
return creds_array_[i];
}
grpc_core::RefCountedPtr<grpc_call_credentials>& get_mutable(size_t i) {
GPR_DEBUG_ASSERT(i < num_creds_);
return creds_array_[i];
}
size_t size() const { return num_creds_; }
private:
grpc_core::RefCountedPtr<grpc_call_credentials>* creds_array_ = nullptr;
size_t num_creds_ = 0;
size_t capacity_ = 0;
};
/* -- Composite channel credentials. -- */
typedef struct {
grpc_channel_credentials base;
grpc_channel_credentials* inner_creds;
grpc_call_credentials* call_creds;
} grpc_composite_channel_credentials;
class grpc_composite_channel_credentials : public grpc_channel_credentials {
public:
grpc_composite_channel_credentials(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds)
: grpc_channel_credentials(channel_creds->type()),
inner_creds_(std::move(channel_creds)),
call_creds_(std::move(call_creds)) {}
~grpc_composite_channel_credentials() override = default;
grpc_core::RefCountedPtr<grpc_channel_credentials>
duplicate_without_call_credentials() override {
return inner_creds_;
}
grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) override;
const grpc_channel_credentials* inner_creds() const {
return inner_creds_.get();
}
const grpc_call_credentials* call_creds() const { return call_creds_.get(); }
grpc_call_credentials* mutable_call_creds() { return call_creds_.get(); }
private:
grpc_core::RefCountedPtr<grpc_channel_credentials> inner_creds_;
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds_;
};
/* -- Composite call credentials. -- */
typedef struct {
grpc_call_credentials base;
grpc_call_credentials_array inner;
} grpc_composite_call_credentials;
class grpc_composite_call_credentials : public grpc_call_credentials {
public:
grpc_composite_call_credentials(
grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
grpc_core::RefCountedPtr<grpc_call_credentials> creds2);
~grpc_composite_call_credentials() override = default;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
const grpc_call_credentials_array& inner() const { return inner_; }
private:
void push_to_inner(grpc_core::RefCountedPtr<grpc_call_credentials> creds,
bool is_composite);
grpc_call_credentials_array inner_;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_COMPOSITE_COMPOSITE_CREDENTIALS_H \
*/

@ -39,120 +39,24 @@
/* -- Common. -- */
grpc_credentials_metadata_request* grpc_credentials_metadata_request_create(
grpc_call_credentials* creds) {
grpc_credentials_metadata_request* r =
static_cast<grpc_credentials_metadata_request*>(
gpr_zalloc(sizeof(grpc_credentials_metadata_request)));
r->creds = grpc_call_credentials_ref(creds);
return r;
}
void grpc_credentials_metadata_request_destroy(
grpc_credentials_metadata_request* r) {
grpc_call_credentials_unref(r->creds);
grpc_http_response_destroy(&r->response);
gpr_free(r);
}
grpc_channel_credentials* grpc_channel_credentials_ref(
grpc_channel_credentials* creds) {
if (creds == nullptr) return nullptr;
gpr_ref(&creds->refcount);
return creds;
}
void grpc_channel_credentials_unref(grpc_channel_credentials* creds) {
if (creds == nullptr) return;
if (gpr_unref(&creds->refcount)) {
if (creds->vtable->destruct != nullptr) {
creds->vtable->destruct(creds);
}
gpr_free(creds);
}
}
void grpc_channel_credentials_release(grpc_channel_credentials* creds) {
GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds));
grpc_core::ExecCtx exec_ctx;
grpc_channel_credentials_unref(creds);
}
grpc_call_credentials* grpc_call_credentials_ref(grpc_call_credentials* creds) {
if (creds == nullptr) return nullptr;
gpr_ref(&creds->refcount);
return creds;
}
void grpc_call_credentials_unref(grpc_call_credentials* creds) {
if (creds == nullptr) return;
if (gpr_unref(&creds->refcount)) {
if (creds->vtable->destruct != nullptr) {
creds->vtable->destruct(creds);
}
gpr_free(creds);
}
if (creds) creds->Unref();
}
void grpc_call_credentials_release(grpc_call_credentials* creds) {
GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds));
grpc_core::ExecCtx exec_ctx;
grpc_call_credentials_unref(creds);
}
bool grpc_call_credentials_get_request_metadata(
grpc_call_credentials* creds, grpc_polling_entity* pollent,
grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata, grpc_error** error) {
if (creds == nullptr || creds->vtable->get_request_metadata == nullptr) {
return true;
}
return creds->vtable->get_request_metadata(creds, pollent, context, md_array,
on_request_metadata, error);
}
void grpc_call_credentials_cancel_get_request_metadata(
grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
if (creds == nullptr ||
creds->vtable->cancel_get_request_metadata == nullptr) {
return;
}
creds->vtable->cancel_get_request_metadata(creds, md_array, error);
}
grpc_security_status grpc_channel_credentials_create_security_connector(
grpc_channel_credentials* channel_creds, const char* target,
const grpc_channel_args* args, grpc_channel_security_connector** sc,
grpc_channel_args** new_args) {
*new_args = nullptr;
if (channel_creds == nullptr) {
return GRPC_SECURITY_ERROR;
}
GPR_ASSERT(channel_creds->vtable->create_security_connector != nullptr);
return channel_creds->vtable->create_security_connector(
channel_creds, nullptr, target, args, sc, new_args);
}
grpc_channel_credentials*
grpc_channel_credentials_duplicate_without_call_credentials(
grpc_channel_credentials* channel_creds) {
if (channel_creds != nullptr && channel_creds->vtable != nullptr &&
channel_creds->vtable->duplicate_without_call_credentials != nullptr) {
return channel_creds->vtable->duplicate_without_call_credentials(
channel_creds);
} else {
return grpc_channel_credentials_ref(channel_creds);
}
if (creds) creds->Unref();
}
static void credentials_pointer_arg_destroy(void* p) {
grpc_channel_credentials_unref(static_cast<grpc_channel_credentials*>(p));
static_cast<grpc_channel_credentials*>(p)->Unref();
}
static void* credentials_pointer_arg_copy(void* p) {
return grpc_channel_credentials_ref(
static_cast<grpc_channel_credentials*>(p));
return static_cast<grpc_channel_credentials*>(p)->Ref().release();
}
static int credentials_pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
@ -191,63 +95,35 @@ grpc_channel_credentials* grpc_channel_credentials_find_in_args(
return nullptr;
}
grpc_server_credentials* grpc_server_credentials_ref(
grpc_server_credentials* creds) {
if (creds == nullptr) return nullptr;
gpr_ref(&creds->refcount);
return creds;
}
void grpc_server_credentials_unref(grpc_server_credentials* creds) {
if (creds == nullptr) return;
if (gpr_unref(&creds->refcount)) {
if (creds->vtable->destruct != nullptr) {
creds->vtable->destruct(creds);
}
if (creds->processor.destroy != nullptr &&
creds->processor.state != nullptr) {
creds->processor.destroy(creds->processor.state);
}
gpr_free(creds);
}
}
void grpc_server_credentials_release(grpc_server_credentials* creds) {
GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds));
grpc_core::ExecCtx exec_ctx;
grpc_server_credentials_unref(creds);
if (creds) creds->Unref();
}
grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials* creds, grpc_server_security_connector** sc) {
if (creds == nullptr || creds->vtable->create_security_connector == nullptr) {
gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
return GRPC_SECURITY_ERROR;
}
return creds->vtable->create_security_connector(creds, sc);
}
void grpc_server_credentials_set_auth_metadata_processor(
grpc_server_credentials* creds, grpc_auth_metadata_processor processor) {
void grpc_server_credentials::set_auth_metadata_processor(
const grpc_auth_metadata_processor& processor) {
GRPC_API_TRACE(
"grpc_server_credentials_set_auth_metadata_processor("
"creds=%p, "
"processor=grpc_auth_metadata_processor { process: %p, state: %p })",
3, (creds, (void*)(intptr_t)processor.process, processor.state));
if (creds == nullptr) return;
if (creds->processor.destroy != nullptr &&
creds->processor.state != nullptr) {
creds->processor.destroy(creds->processor.state);
}
creds->processor = processor;
3, (this, (void*)(intptr_t)processor.process, processor.state));
DestroyProcessor();
processor_ = processor;
}
void grpc_server_credentials_set_auth_metadata_processor(
grpc_server_credentials* creds, grpc_auth_metadata_processor processor) {
GPR_DEBUG_ASSERT(creds != nullptr);
creds->set_auth_metadata_processor(processor);
}
static void server_credentials_pointer_arg_destroy(void* p) {
grpc_server_credentials_unref(static_cast<grpc_server_credentials*>(p));
static_cast<grpc_server_credentials*>(p)->Unref();
}
static void* server_credentials_pointer_arg_copy(void* p) {
return grpc_server_credentials_ref(static_cast<grpc_server_credentials*>(p));
return static_cast<grpc_server_credentials*>(p)->Ref().release();
}
static int server_credentials_pointer_cmp(void* a, void* b) {

@ -26,6 +26,7 @@
#include <grpc/support/sync.h>
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/polling_entity.h"
@ -90,44 +91,46 @@ void grpc_override_well_known_credentials_path_getter(
#define GRPC_ARG_CHANNEL_CREDENTIALS "grpc.channel_credentials"
typedef struct {
void (*destruct)(grpc_channel_credentials* c);
grpc_security_status (*create_security_connector)(
grpc_channel_credentials* c, grpc_call_credentials* call_creds,
// This type is forward declared as a C struct and we cannot define it as a
// class. Otherwise, compiler will complain about type mismatch due to
// -Wmismatched-tags.
struct grpc_channel_credentials
: grpc_core::RefCounted<grpc_channel_credentials> {
public:
explicit grpc_channel_credentials(const char* type) : type_(type) {}
virtual ~grpc_channel_credentials() = default;
// Creates a security connector for the channel. May also create new channel
// args for the channel to be used in place of the passed in const args if
// returned non NULL. In that case the caller is responsible for destroying
// new_args after channel creation.
virtual grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_security_connector** sc, grpc_channel_args** new_args);
grpc_channel_credentials* (*duplicate_without_call_credentials)(
grpc_channel_credentials* c);
} grpc_channel_credentials_vtable;
struct grpc_channel_credentials {
const grpc_channel_credentials_vtable* vtable;
const char* type;
gpr_refcount refcount;
grpc_channel_args** new_args) {
// Tell clang-tidy that call_creds cannot be passed as const-ref.
call_creds.reset();
GRPC_ABSTRACT;
}
// Creates a version of the channel credentials without any attached call
// credentials. This can be used in order to open a channel to a non-trusted
// gRPC load balancer.
virtual grpc_core::RefCountedPtr<grpc_channel_credentials>
duplicate_without_call_credentials() {
// By default we just increment the refcount.
return Ref();
}
const char* type() const { return type_; }
GRPC_ABSTRACT_BASE_CLASS
private:
const char* type_;
};
grpc_channel_credentials* grpc_channel_credentials_ref(
grpc_channel_credentials* creds);
void grpc_channel_credentials_unref(grpc_channel_credentials* creds);
/* Creates a security connector for the channel. May also create new channel
args for the channel to be used in place of the passed in const args if
returned non NULL. In that case the caller is responsible for destroying
new_args after channel creation. */
grpc_security_status grpc_channel_credentials_create_security_connector(
grpc_channel_credentials* creds, const char* target,
const grpc_channel_args* args, grpc_channel_security_connector** sc,
grpc_channel_args** new_args);
/* Creates a version of the channel credentials without any attached call
credentials. This can be used in order to open a channel to a non-trusted
gRPC load balancer. */
grpc_channel_credentials*
grpc_channel_credentials_duplicate_without_call_credentials(
grpc_channel_credentials* creds);
/* Util to encapsulate the channel credentials in a channel arg. */
grpc_arg grpc_channel_credentials_to_arg(grpc_channel_credentials* credentials);
@ -158,44 +161,39 @@ void grpc_credentials_mdelem_array_destroy(grpc_credentials_mdelem_array* list);
/* --- grpc_call_credentials. --- */
typedef struct {
void (*destruct)(grpc_call_credentials* c);
bool (*get_request_metadata)(grpc_call_credentials* c,
grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error);
void (*cancel_get_request_metadata)(grpc_call_credentials* c,
grpc_credentials_mdelem_array* md_array,
grpc_error* error);
} grpc_call_credentials_vtable;
struct grpc_call_credentials {
const grpc_call_credentials_vtable* vtable;
const char* type;
gpr_refcount refcount;
// This type is forward declared as a C struct and we cannot define it as a
// class. Otherwise, compiler will complain about type mismatch due to
// -Wmismatched-tags.
struct grpc_call_credentials
: public grpc_core::RefCounted<grpc_call_credentials> {
public:
explicit grpc_call_credentials(const char* type) : type_(type) {}
virtual ~grpc_call_credentials() = default;
// Returns true if completed synchronously, in which case \a error will
// be set to indicate the result. Otherwise, \a on_request_metadata will
// be invoked asynchronously when complete. \a md_array will be populated
// with the resulting metadata once complete.
virtual bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) GRPC_ABSTRACT;
// Cancels a pending asynchronous operation started by
// grpc_call_credentials_get_request_metadata() with the corresponding
// value of \a md_array.
virtual void cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) GRPC_ABSTRACT;
const char* type() const { return type_; }
GRPC_ABSTRACT_BASE_CLASS
private:
const char* type_;
};
grpc_call_credentials* grpc_call_credentials_ref(grpc_call_credentials* creds);
void grpc_call_credentials_unref(grpc_call_credentials* creds);
/// Returns true if completed synchronously, in which case \a error will
/// be set to indicate the result. Otherwise, \a on_request_metadata will
/// be invoked asynchronously when complete. \a md_array will be populated
/// with the resulting metadata once complete.
bool grpc_call_credentials_get_request_metadata(
grpc_call_credentials* creds, grpc_polling_entity* pollent,
grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata, grpc_error** error);
/// Cancels a pending asynchronous operation started by
/// grpc_call_credentials_get_request_metadata() with the corresponding
/// value of \a md_array.
void grpc_call_credentials_cancel_get_request_metadata(
grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array,
grpc_error* error);
/* Metadata-only credentials with the specified key and value where
asynchronicity can be simulated for testing. */
grpc_call_credentials* grpc_md_only_test_credentials_create(
@ -203,26 +201,40 @@ grpc_call_credentials* grpc_md_only_test_credentials_create(
/* --- grpc_server_credentials. --- */
typedef struct {
void (*destruct)(grpc_server_credentials* c);
grpc_security_status (*create_security_connector)(
grpc_server_credentials* c, grpc_server_security_connector** sc);
} grpc_server_credentials_vtable;
struct grpc_server_credentials {
const grpc_server_credentials_vtable* vtable;
const char* type;
gpr_refcount refcount;
grpc_auth_metadata_processor processor;
};
// This type is forward declared as a C struct and we cannot define it as a
// class. Otherwise, compiler will complain about type mismatch due to
// -Wmismatched-tags.
struct grpc_server_credentials
: public grpc_core::RefCounted<grpc_server_credentials> {
public:
explicit grpc_server_credentials(const char* type) : type_(type) {}
grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials* creds, grpc_server_security_connector** sc);
virtual ~grpc_server_credentials() { DestroyProcessor(); }
grpc_server_credentials* grpc_server_credentials_ref(
grpc_server_credentials* creds);
virtual grpc_core::RefCountedPtr<grpc_server_security_connector>
create_security_connector() GRPC_ABSTRACT;
void grpc_server_credentials_unref(grpc_server_credentials* creds);
const char* type() const { return type_; }
const grpc_auth_metadata_processor& auth_metadata_processor() const {
return processor_;
}
void set_auth_metadata_processor(
const grpc_auth_metadata_processor& processor);
GRPC_ABSTRACT_BASE_CLASS
private:
void DestroyProcessor() {
if (processor_.destroy != nullptr && processor_.state != nullptr) {
processor_.destroy(processor_.state);
}
}
const char* type_;
grpc_auth_metadata_processor processor_ =
grpc_auth_metadata_processor(); // Zero-initialize the C struct.
};
#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials"
@ -233,15 +245,27 @@ grpc_server_credentials* grpc_find_server_credentials_in_args(
/* -- Credentials Metadata Request. -- */
typedef struct {
grpc_call_credentials* creds;
struct grpc_credentials_metadata_request {
explicit grpc_credentials_metadata_request(
grpc_core::RefCountedPtr<grpc_call_credentials> creds)
: creds(std::move(creds)) {}
~grpc_credentials_metadata_request() {
grpc_http_response_destroy(&response);
}
grpc_core::RefCountedPtr<grpc_call_credentials> creds;
grpc_http_response response;
} grpc_credentials_metadata_request;
};
grpc_credentials_metadata_request* grpc_credentials_metadata_request_create(
grpc_call_credentials* creds);
inline grpc_credentials_metadata_request*
grpc_credentials_metadata_request_create(
grpc_core::RefCountedPtr<grpc_call_credentials> creds) {
return grpc_core::New<grpc_credentials_metadata_request>(std::move(creds));
}
void grpc_credentials_metadata_request_destroy(
grpc_credentials_metadata_request* r);
inline void grpc_credentials_metadata_request_destroy(
grpc_credentials_metadata_request* r) {
grpc_core::Delete(r);
}
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H */

@ -33,49 +33,45 @@
/* -- Fake transport security credentials. -- */
static grpc_security_status fake_transport_security_create_security_connector(
grpc_channel_credentials* c, grpc_call_credentials* call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
*sc =
grpc_fake_channel_security_connector_create(c, call_creds, target, args);
return GRPC_SECURITY_OK;
}
static grpc_security_status
fake_transport_security_server_create_security_connector(
grpc_server_credentials* c, grpc_server_security_connector** sc) {
*sc = grpc_fake_server_security_connector_create(c);
return GRPC_SECURITY_OK;
}
namespace {
class grpc_fake_channel_credentials final : public grpc_channel_credentials {
public:
grpc_fake_channel_credentials()
: grpc_channel_credentials(
GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) {}
~grpc_fake_channel_credentials() override = default;
grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) override {
return grpc_fake_channel_security_connector_create(
this->Ref(), std::move(call_creds), target, args);
}
};
class grpc_fake_server_credentials final : public grpc_server_credentials {
public:
grpc_fake_server_credentials()
: grpc_server_credentials(
GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) {}
~grpc_fake_server_credentials() override = default;
grpc_core::RefCountedPtr<grpc_server_security_connector>
create_security_connector() override {
return grpc_fake_server_security_connector_create(this->Ref());
}
};
} // namespace
static grpc_channel_credentials_vtable
fake_transport_security_credentials_vtable = {
nullptr, fake_transport_security_create_security_connector, nullptr};
static grpc_server_credentials_vtable
fake_transport_security_server_credentials_vtable = {
nullptr, fake_transport_security_server_create_security_connector};
grpc_channel_credentials* grpc_fake_transport_security_credentials_create(
void) {
grpc_channel_credentials* c = static_cast<grpc_channel_credentials*>(
gpr_zalloc(sizeof(grpc_channel_credentials)));
c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
c->vtable = &fake_transport_security_credentials_vtable;
gpr_ref_init(&c->refcount, 1);
return c;
grpc_channel_credentials* grpc_fake_transport_security_credentials_create() {
return grpc_core::New<grpc_fake_channel_credentials>();
}
grpc_server_credentials* grpc_fake_transport_security_server_credentials_create(
void) {
grpc_server_credentials* c = static_cast<grpc_server_credentials*>(
gpr_malloc(sizeof(grpc_server_credentials)));
memset(c, 0, sizeof(grpc_server_credentials));
c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
gpr_ref_init(&c->refcount, 1);
c->vtable = &fake_transport_security_server_credentials_vtable;
return c;
grpc_server_credentials*
grpc_fake_transport_security_server_credentials_create() {
return grpc_core::New<grpc_fake_server_credentials>();
}
grpc_arg grpc_fake_transport_expected_targets_arg(char* expected_targets) {
@ -92,46 +88,25 @@ const char* grpc_fake_transport_get_expected_targets(
/* -- Metadata-only test credentials. -- */
static void md_only_test_destruct(grpc_call_credentials* creds) {
grpc_md_only_test_credentials* c =
reinterpret_cast<grpc_md_only_test_credentials*>(creds);
GRPC_MDELEM_UNREF(c->md);
}
static bool md_only_test_get_request_metadata(
grpc_call_credentials* creds, grpc_polling_entity* pollent,
grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata, grpc_error** error) {
grpc_md_only_test_credentials* c =
reinterpret_cast<grpc_md_only_test_credentials*>(creds);
grpc_credentials_mdelem_array_add(md_array, c->md);
if (c->is_async) {
bool grpc_md_only_test_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_credentials_mdelem_array_add(md_array, md_);
if (is_async_) {
GRPC_CLOSURE_SCHED(on_request_metadata, GRPC_ERROR_NONE);
return false;
}
return true;
}
static void md_only_test_cancel_get_request_metadata(
grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
void grpc_md_only_test_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
static grpc_call_credentials_vtable md_only_test_vtable = {
md_only_test_destruct, md_only_test_get_request_metadata,
md_only_test_cancel_get_request_metadata};
grpc_call_credentials* grpc_md_only_test_credentials_create(
const char* md_key, const char* md_value, bool is_async) {
grpc_md_only_test_credentials* c =
static_cast<grpc_md_only_test_credentials*>(
gpr_zalloc(sizeof(grpc_md_only_test_credentials)));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
c->base.vtable = &md_only_test_vtable;
gpr_ref_init(&c->base.refcount, 1);
c->md = grpc_mdelem_from_slices(grpc_slice_from_copied_string(md_key),
grpc_slice_from_copied_string(md_value));
c->is_async = is_async;
return &c->base;
return grpc_core::New<grpc_md_only_test_credentials>(md_key, md_value,
is_async);
}

@ -55,10 +55,28 @@ const char* grpc_fake_transport_get_expected_targets(
/* -- Metadata-only Test credentials. -- */
typedef struct {
grpc_call_credentials base;
grpc_mdelem md;
bool is_async;
} grpc_md_only_test_credentials;
class grpc_md_only_test_credentials : public grpc_call_credentials {
public:
grpc_md_only_test_credentials(const char* md_key, const char* md_value,
bool is_async)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2),
md_(grpc_mdelem_from_slices(grpc_slice_from_copied_string(md_key),
grpc_slice_from_copied_string(md_value))),
is_async_(is_async) {}
~grpc_md_only_test_credentials() override { GRPC_MDELEM_UNREF(md_); }
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
private:
grpc_mdelem md_;
bool is_async_;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H */

@ -30,6 +30,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/load_file.h"
@ -72,20 +73,11 @@ typedef struct {
grpc_http_response response;
} metadata_server_detector;
static void google_default_credentials_destruct(
grpc_channel_credentials* creds) {
grpc_google_default_channel_credentials* c =
reinterpret_cast<grpc_google_default_channel_credentials*>(creds);
grpc_channel_credentials_unref(c->alts_creds);
grpc_channel_credentials_unref(c->ssl_creds);
}
static grpc_security_status google_default_create_security_connector(
grpc_channel_credentials* creds, grpc_call_credentials* call_creds,
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_google_default_channel_credentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
grpc_google_default_channel_credentials* c =
reinterpret_cast<grpc_google_default_channel_credentials*>(creds);
grpc_channel_args** new_args) {
bool is_grpclb_load_balancer = grpc_channel_arg_get_bool(
grpc_channel_args_find(args, GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER),
false);
@ -95,22 +87,22 @@ static grpc_security_status google_default_create_security_connector(
false);
bool use_alts =
is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer;
grpc_security_status status = GRPC_SECURITY_ERROR;
/* Return failure if ALTS is selected but not running on GCE. */
if (use_alts && !g_is_on_gce) {
gpr_log(GPR_ERROR, "ALTS is selected, but not running on GCE.");
goto end;
return nullptr;
}
status = use_alts ? c->alts_creds->vtable->create_security_connector(
c->alts_creds, call_creds, target, args, sc, new_args)
: c->ssl_creds->vtable->create_security_connector(
c->ssl_creds, call_creds, target, args, sc, new_args);
/* grpclb-specific channel args are removed from the channel args set
* to ensure backends and fallback adresses will have the same set of channel
* args. By doing that, it guarantees the connections to backends will not be
* torn down and re-connected when switching in and out of fallback mode.
*/
end:
grpc_core::RefCountedPtr<grpc_channel_security_connector> sc =
use_alts ? alts_creds_->create_security_connector(call_creds, target,
args, new_args)
: ssl_creds_->create_security_connector(call_creds, target, args,
new_args);
/* grpclb-specific channel args are removed from the channel args set
* to ensure backends and fallback adresses will have the same set of channel
* args. By doing that, it guarantees the connections to backends will not be
* torn down and re-connected when switching in and out of fallback mode.
*/
if (use_alts) {
static const char* args_to_remove[] = {
GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER,
@ -119,13 +111,9 @@ end:
*new_args = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), nullptr, 0);
}
return status;
return sc;
}
static grpc_channel_credentials_vtable google_default_credentials_vtable = {
google_default_credentials_destruct,
google_default_create_security_connector, nullptr};
static void on_metadata_server_detection_http_response(void* user_data,
grpc_error* error) {
metadata_server_detector* detector =
@ -215,11 +203,11 @@ static int is_metadata_server_reachable() {
/* Takes ownership of creds_path if not NULL. */
static grpc_error* create_default_creds_from_path(
char* creds_path, grpc_call_credentials** creds) {
char* creds_path, grpc_core::RefCountedPtr<grpc_call_credentials>* creds) {
grpc_json* json = nullptr;
grpc_auth_json_key key;
grpc_auth_refresh_token token;
grpc_call_credentials* result = nullptr;
grpc_core::RefCountedPtr<grpc_call_credentials> result;
grpc_slice creds_data = grpc_empty_slice();
grpc_error* error = GRPC_ERROR_NONE;
if (creds_path == nullptr) {
@ -276,9 +264,9 @@ end:
return error;
}
grpc_channel_credentials* grpc_google_default_credentials_create(void) {
grpc_channel_credentials* grpc_google_default_credentials_create() {
grpc_channel_credentials* result = nullptr;
grpc_call_credentials* call_creds = nullptr;
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds;
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Failed to create Google credentials");
grpc_error* err;
@ -316,7 +304,8 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
gpr_mu_unlock(&g_state_mu);
if (g_metadata_server_available) {
call_creds = grpc_google_compute_engine_credentials_create(nullptr);
call_creds = grpc_core::RefCountedPtr<grpc_call_credentials>(
grpc_google_compute_engine_credentials_create(nullptr));
if (call_creds == nullptr) {
error = grpc_error_add_child(
error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@ -327,23 +316,23 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
end:
if (call_creds != nullptr) {
/* Create google default credentials. */
auto creds = static_cast<grpc_google_default_channel_credentials*>(
gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
creds->base.vtable = &google_default_credentials_vtable;
creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
gpr_ref_init(&creds->base.refcount, 1);
creds->ssl_creds =
grpc_channel_credentials* ssl_creds =
grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
GPR_ASSERT(creds->ssl_creds != nullptr);
GPR_ASSERT(ssl_creds != nullptr);
grpc_alts_credentials_options* options =
grpc_alts_credentials_client_options_create();
creds->alts_creds = grpc_alts_credentials_create(options);
grpc_channel_credentials* alts_creds =
grpc_alts_credentials_create(options);
grpc_alts_credentials_options_destroy(options);
result = grpc_composite_channel_credentials_create(&creds->base, call_creds,
nullptr);
auto creds =
grpc_core::MakeRefCounted<grpc_google_default_channel_credentials>(
alts_creds != nullptr ? alts_creds->Ref() : nullptr,
ssl_creds != nullptr ? ssl_creds->Ref() : nullptr);
if (ssl_creds) ssl_creds->Unref();
if (alts_creds) alts_creds->Unref();
result = grpc_composite_channel_credentials_create(
creds.get(), call_creds.get(), nullptr);
GPR_ASSERT(result != nullptr);
grpc_channel_credentials_unref(&creds->base);
grpc_call_credentials_unref(call_creds);
} else {
gpr_log(GPR_ERROR, "Could not create google default credentials: %s",
grpc_error_string(error));

@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/credentials/credentials.h"
#define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud"
@ -39,11 +40,33 @@
"/" GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE
#endif
typedef struct {
grpc_channel_credentials base;
grpc_channel_credentials* alts_creds;
grpc_channel_credentials* ssl_creds;
} grpc_google_default_channel_credentials;
class grpc_google_default_channel_credentials
: public grpc_channel_credentials {
public:
grpc_google_default_channel_credentials(
grpc_core::RefCountedPtr<grpc_channel_credentials> alts_creds,
grpc_core::RefCountedPtr<grpc_channel_credentials> ssl_creds)
: grpc_channel_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT),
alts_creds_(std::move(alts_creds)),
ssl_creds_(std::move(ssl_creds)) {}
~grpc_google_default_channel_credentials() override = default;
grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) override;
const grpc_channel_credentials* alts_creds() const {
return alts_creds_.get();
}
const grpc_channel_credentials* ssl_creds() const { return ssl_creds_.get(); }
private:
grpc_core::RefCountedPtr<grpc_channel_credentials> alts_creds_;
grpc_core::RefCountedPtr<grpc_channel_credentials> ssl_creds_;
};
namespace grpc_core {
namespace internal {

@ -22,6 +22,7 @@
#include <string.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/surface/api_trace.h"
#include <grpc/support/alloc.h>
@ -29,32 +30,37 @@
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
static void iam_destruct(grpc_call_credentials* creds) {
grpc_google_iam_credentials* c =
reinterpret_cast<grpc_google_iam_credentials*>(creds);
grpc_credentials_mdelem_array_destroy(&c->md_array);
grpc_google_iam_credentials::~grpc_google_iam_credentials() {
grpc_credentials_mdelem_array_destroy(&md_array_);
}
static bool iam_get_request_metadata(grpc_call_credentials* creds,
grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_google_iam_credentials* c =
reinterpret_cast<grpc_google_iam_credentials*>(creds);
grpc_credentials_mdelem_array_append(md_array, &c->md_array);
bool grpc_google_iam_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_credentials_mdelem_array_append(md_array, &md_array_);
return true;
}
static void iam_cancel_get_request_metadata(
grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
void grpc_google_iam_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
static grpc_call_credentials_vtable iam_vtable = {
iam_destruct, iam_get_request_metadata, iam_cancel_get_request_metadata};
grpc_google_iam_credentials::grpc_google_iam_credentials(
const char* token, const char* authority_selector)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_IAM) {
grpc_mdelem md = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY),
grpc_slice_from_copied_string(token));
grpc_credentials_mdelem_array_add(&md_array_, md);
GRPC_MDELEM_UNREF(md);
md = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY),
grpc_slice_from_copied_string(authority_selector));
grpc_credentials_mdelem_array_add(&md_array_, md);
GRPC_MDELEM_UNREF(md);
}
grpc_call_credentials* grpc_google_iam_credentials_create(
const char* token, const char* authority_selector, void* reserved) {
@ -66,21 +72,7 @@ grpc_call_credentials* grpc_google_iam_credentials_create(
GPR_ASSERT(reserved == nullptr);
GPR_ASSERT(token != nullptr);
GPR_ASSERT(authority_selector != nullptr);
grpc_google_iam_credentials* c =
static_cast<grpc_google_iam_credentials*>(gpr_zalloc(sizeof(*c)));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM;
c->base.vtable = &iam_vtable;
gpr_ref_init(&c->base.refcount, 1);
grpc_mdelem md = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY),
grpc_slice_from_copied_string(token));
grpc_credentials_mdelem_array_add(&c->md_array, md);
GRPC_MDELEM_UNREF(md);
md = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY),
grpc_slice_from_copied_string(authority_selector));
grpc_credentials_mdelem_array_add(&c->md_array, md);
GRPC_MDELEM_UNREF(md);
return &c->base;
return grpc_core::MakeRefCounted<grpc_google_iam_credentials>(
token, authority_selector)
.release();
}

@ -23,9 +23,23 @@
#include "src/core/lib/security/credentials/credentials.h"
typedef struct {
grpc_call_credentials base;
grpc_credentials_mdelem_array md_array;
} grpc_google_iam_credentials;
class grpc_google_iam_credentials : public grpc_call_credentials {
public:
grpc_google_iam_credentials(const char* token,
const char* authority_selector);
~grpc_google_iam_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
private:
grpc_credentials_mdelem_array md_array_;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_IAM_IAM_CREDENTIALS_H */

@ -23,6 +23,8 @@
#include <inttypes.h>
#include <string.h>
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/surface/api_trace.h"
#include <grpc/support/alloc.h>
@ -30,71 +32,66 @@
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
static void jwt_reset_cache(grpc_service_account_jwt_access_credentials* c) {
GRPC_MDELEM_UNREF(c->cached.jwt_md);
c->cached.jwt_md = GRPC_MDNULL;
if (c->cached.service_url != nullptr) {
gpr_free(c->cached.service_url);
c->cached.service_url = nullptr;
void grpc_service_account_jwt_access_credentials::reset_cache() {
GRPC_MDELEM_UNREF(cached_.jwt_md);
cached_.jwt_md = GRPC_MDNULL;
if (cached_.service_url != nullptr) {
gpr_free(cached_.service_url);
cached_.service_url = nullptr;
}
c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
cached_.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
}
static void jwt_destruct(grpc_call_credentials* creds) {
grpc_service_account_jwt_access_credentials* c =
reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
grpc_auth_json_key_destruct(&c->key);
jwt_reset_cache(c);
gpr_mu_destroy(&c->cache_mu);
grpc_service_account_jwt_access_credentials::
~grpc_service_account_jwt_access_credentials() {
grpc_auth_json_key_destruct(&key_);
reset_cache();
gpr_mu_destroy(&cache_mu_);
}
static bool jwt_get_request_metadata(grpc_call_credentials* creds,
grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_service_account_jwt_access_credentials* c =
reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
bool grpc_service_account_jwt_access_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
gpr_timespec refresh_threshold = gpr_time_from_seconds(
GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
/* See if we can return a cached jwt. */
grpc_mdelem jwt_md = GRPC_MDNULL;
{
gpr_mu_lock(&c->cache_mu);
if (c->cached.service_url != nullptr &&
strcmp(c->cached.service_url, context.service_url) == 0 &&
!GRPC_MDISNULL(c->cached.jwt_md) &&
(gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
gpr_now(GPR_CLOCK_REALTIME)),
refresh_threshold) > 0)) {
jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md);
gpr_mu_lock(&cache_mu_);
if (cached_.service_url != nullptr &&
strcmp(cached_.service_url, context.service_url) == 0 &&
!GRPC_MDISNULL(cached_.jwt_md) &&
(gpr_time_cmp(
gpr_time_sub(cached_.jwt_expiration, gpr_now(GPR_CLOCK_REALTIME)),
refresh_threshold) > 0)) {
jwt_md = GRPC_MDELEM_REF(cached_.jwt_md);
}
gpr_mu_unlock(&c->cache_mu);
gpr_mu_unlock(&cache_mu_);
}
if (GRPC_MDISNULL(jwt_md)) {
char* jwt = nullptr;
/* Generate a new jwt. */
gpr_mu_lock(&c->cache_mu);
jwt_reset_cache(c);
jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url,
c->jwt_lifetime, nullptr);
gpr_mu_lock(&cache_mu_);
reset_cache();
jwt = grpc_jwt_encode_and_sign(&key_, context.service_url, jwt_lifetime_,
nullptr);
if (jwt != nullptr) {
char* md_value;
gpr_asprintf(&md_value, "Bearer %s", jwt);
gpr_free(jwt);
c->cached.jwt_expiration =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
c->cached.service_url = gpr_strdup(context.service_url);
c->cached.jwt_md = grpc_mdelem_from_slices(
cached_.jwt_expiration =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), jwt_lifetime_);
cached_.service_url = gpr_strdup(context.service_url);
cached_.jwt_md = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY),
grpc_slice_from_copied_string(md_value));
gpr_free(md_value);
jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md);
jwt_md = GRPC_MDELEM_REF(cached_.jwt_md);
}
gpr_mu_unlock(&c->cache_mu);
gpr_mu_unlock(&cache_mu_);
}
if (!GRPC_MDISNULL(jwt_md)) {
@ -106,29 +103,15 @@ static bool jwt_get_request_metadata(grpc_call_credentials* creds,
return true;
}
static void jwt_cancel_get_request_metadata(
grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
void grpc_service_account_jwt_access_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
static grpc_call_credentials_vtable jwt_vtable = {
jwt_destruct, jwt_get_request_metadata, jwt_cancel_get_request_metadata};
grpc_call_credentials*
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime) {
grpc_service_account_jwt_access_credentials* c;
if (!grpc_auth_json_key_is_valid(&key)) {
gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
return nullptr;
}
c = static_cast<grpc_service_account_jwt_access_credentials*>(
gpr_zalloc(sizeof(grpc_service_account_jwt_access_credentials)));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT;
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &jwt_vtable;
c->key = key;
grpc_service_account_jwt_access_credentials::
grpc_service_account_jwt_access_credentials(grpc_auth_json_key key,
gpr_timespec token_lifetime)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_JWT), key_(key) {
gpr_timespec max_token_lifetime = grpc_max_auth_token_lifetime();
if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) {
gpr_log(GPR_INFO,
@ -136,10 +119,20 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
static_cast<int>(max_token_lifetime.tv_sec));
token_lifetime = grpc_max_auth_token_lifetime();
}
c->jwt_lifetime = token_lifetime;
gpr_mu_init(&c->cache_mu);
jwt_reset_cache(c);
return &c->base;
jwt_lifetime_ = token_lifetime;
gpr_mu_init(&cache_mu_);
reset_cache();
}
grpc_core::RefCountedPtr<grpc_call_credentials>
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime) {
if (!grpc_auth_json_key_is_valid(&key)) {
gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
return nullptr;
}
return grpc_core::MakeRefCounted<grpc_service_account_jwt_access_credentials>(
key, token_lifetime);
}
static char* redact_private_key(const char* json_key) {
@ -182,9 +175,7 @@ grpc_call_credentials* grpc_service_account_jwt_access_credentials_create(
}
GPR_ASSERT(reserved == nullptr);
grpc_core::ExecCtx exec_ctx;
grpc_call_credentials* creds =
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key_create_from_string(json_key), token_lifetime);
return creds;
return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key_create_from_string(json_key), token_lifetime)
.release();
}

@ -24,25 +24,44 @@
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/jwt/json_token.h"
typedef struct {
grpc_call_credentials base;
class grpc_service_account_jwt_access_credentials
: public grpc_call_credentials {
public:
grpc_service_account_jwt_access_credentials(grpc_auth_json_key key,
gpr_timespec token_lifetime);
~grpc_service_account_jwt_access_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
const gpr_timespec& jwt_lifetime() const { return jwt_lifetime_; }
const grpc_auth_json_key& key() const { return key_; }
private:
void reset_cache();
// Have a simple cache for now with just 1 entry. We could have a map based on
// the service_url for a more sophisticated one.
gpr_mu cache_mu;
gpr_mu cache_mu_;
struct {
grpc_mdelem jwt_md;
char* service_url;
grpc_mdelem jwt_md = GRPC_MDNULL;
char* service_url = nullptr;
gpr_timespec jwt_expiration;
} cached;
} cached_;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_service_account_jwt_access_credentials;
grpc_auth_json_key key_;
gpr_timespec jwt_lifetime_;
};
// Private constructor for jwt credentials from an already parsed json key.
// Takes ownership of the key.
grpc_call_credentials*
grpc_core::RefCountedPtr<grpc_call_credentials>
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime);

@ -31,7 +31,9 @@
#include <grpc/support/sync.h>
extern "C" {
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
}
#include "src/core/lib/gpr/string.h"

@ -29,49 +29,36 @@
#define GRPC_CREDENTIALS_TYPE_LOCAL "Local"
static void local_credentials_destruct(grpc_channel_credentials* creds) {}
static void local_server_credentials_destruct(grpc_server_credentials* creds) {}
static grpc_security_status local_create_security_connector(
grpc_channel_credentials* creds,
grpc_call_credentials* request_metadata_creds, const char* target_name,
const grpc_channel_args* args, grpc_channel_security_connector** sc,
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_credentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name, const grpc_channel_args* args,
grpc_channel_args** new_args) {
return grpc_local_channel_security_connector_create(
creds, request_metadata_creds, args, target_name, sc);
this->Ref(), std::move(request_metadata_creds), args, target_name);
}
static grpc_security_status local_server_create_security_connector(
grpc_server_credentials* creds, grpc_server_security_connector** sc) {
return grpc_local_server_security_connector_create(creds, sc);
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_credentials::create_security_connector() {
return grpc_local_server_security_connector_create(this->Ref());
}
static const grpc_channel_credentials_vtable local_credentials_vtable = {
local_credentials_destruct, local_create_security_connector,
/*duplicate_without_call_credentials=*/nullptr};
static const grpc_server_credentials_vtable local_server_credentials_vtable = {
local_server_credentials_destruct, local_server_create_security_connector};
grpc_local_credentials::grpc_local_credentials(
grpc_local_connect_type connect_type)
: grpc_channel_credentials(GRPC_CREDENTIALS_TYPE_LOCAL),
connect_type_(connect_type) {}
grpc_channel_credentials* grpc_local_credentials_create(
grpc_local_connect_type connect_type) {
auto creds = static_cast<grpc_local_credentials*>(
gpr_zalloc(sizeof(grpc_local_credentials)));
creds->connect_type = connect_type;
creds->base.type = GRPC_CREDENTIALS_TYPE_LOCAL;
creds->base.vtable = &local_credentials_vtable;
gpr_ref_init(&creds->base.refcount, 1);
return &creds->base;
return grpc_core::New<grpc_local_credentials>(connect_type);
}
grpc_local_server_credentials::grpc_local_server_credentials(
grpc_local_connect_type connect_type)
: grpc_server_credentials(GRPC_CREDENTIALS_TYPE_LOCAL),
connect_type_(connect_type) {}
grpc_server_credentials* grpc_local_server_credentials_create(
grpc_local_connect_type connect_type) {
auto creds = static_cast<grpc_local_server_credentials*>(
gpr_zalloc(sizeof(grpc_local_server_credentials)));
creds->connect_type = connect_type;
creds->base.type = GRPC_CREDENTIALS_TYPE_LOCAL;
creds->base.vtable = &local_server_credentials_vtable;
gpr_ref_init(&creds->base.refcount, 1);
return &creds->base;
return grpc_core::New<grpc_local_server_credentials>(connect_type);
}

@ -25,16 +25,37 @@
#include "src/core/lib/security/credentials/credentials.h"
/* Main struct for grpc local channel credential. */
typedef struct grpc_local_credentials {
grpc_channel_credentials base;
grpc_local_connect_type connect_type;
} grpc_local_credentials;
/* Main struct for grpc local server credential. */
typedef struct grpc_local_server_credentials {
grpc_server_credentials base;
grpc_local_connect_type connect_type;
} grpc_local_server_credentials;
/* Main class for grpc local channel credential. */
class grpc_local_credentials final : public grpc_channel_credentials {
public:
explicit grpc_local_credentials(grpc_local_connect_type connect_type);
~grpc_local_credentials() override = default;
grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name, const grpc_channel_args* args,
grpc_channel_args** new_args) override;
grpc_local_connect_type connect_type() const { return connect_type_; }
private:
grpc_local_connect_type connect_type_;
};
/* Main class for grpc local server credential. */
class grpc_local_server_credentials final : public grpc_server_credentials {
public:
explicit grpc_local_server_credentials(grpc_local_connect_type connect_type);
~grpc_local_server_credentials() override = default;
grpc_core::RefCountedPtr<grpc_server_security_connector>
create_security_connector() override;
grpc_local_connect_type connect_type() const { return connect_type_; }
private:
grpc_local_connect_type connect_type_;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_LOCAL_LOCAL_CREDENTIALS_H */

@ -22,6 +22,7 @@
#include <string.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/util/json_util.h"
#include "src/core/lib/surface/api_trace.h"
@ -105,13 +106,12 @@ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token* refresh_token) {
// Oauth2 Token Fetcher credentials.
//
static void oauth2_token_fetcher_destruct(grpc_call_credentials* creds) {
grpc_oauth2_token_fetcher_credentials* c =
reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(creds);
GRPC_MDELEM_UNREF(c->access_token_md);
gpr_mu_destroy(&c->mu);
grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&c->pollent));
grpc_httpcli_context_destroy(&c->httpcli_context);
grpc_oauth2_token_fetcher_credentials::
~grpc_oauth2_token_fetcher_credentials() {
GRPC_MDELEM_UNREF(access_token_md_);
gpr_mu_destroy(&mu_);
grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&pollent_));
grpc_httpcli_context_destroy(&httpcli_context_);
}
grpc_credentials_status
@ -209,25 +209,29 @@ static void on_oauth2_token_fetcher_http_response(void* user_data,
grpc_credentials_metadata_request* r =
static_cast<grpc_credentials_metadata_request*>(user_data);
grpc_oauth2_token_fetcher_credentials* c =
reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(r->creds);
reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(r->creds.get());
c->on_http_response(r, error);
}
void grpc_oauth2_token_fetcher_credentials::on_http_response(
grpc_credentials_metadata_request* r, grpc_error* error) {
grpc_mdelem access_token_md = GRPC_MDNULL;
grpc_millis token_lifetime;
grpc_credentials_status status =
grpc_oauth2_token_fetcher_credentials_parse_server_response(
&r->response, &access_token_md, &token_lifetime);
// Update cache and grab list of pending requests.
gpr_mu_lock(&c->mu);
c->token_fetch_pending = false;
c->access_token_md = GRPC_MDELEM_REF(access_token_md);
c->token_expiration =
gpr_mu_lock(&mu_);
token_fetch_pending_ = false;
access_token_md_ = GRPC_MDELEM_REF(access_token_md);
token_expiration_ =
status == GRPC_CREDENTIALS_OK
? gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_millis(token_lifetime, GPR_TIMESPAN))
: gpr_inf_past(GPR_CLOCK_MONOTONIC);
grpc_oauth2_pending_get_request_metadata* pending_request =
c->pending_requests;
c->pending_requests = nullptr;
gpr_mu_unlock(&c->mu);
grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_;
pending_requests_ = nullptr;
gpr_mu_unlock(&mu_);
// Invoke callbacks for all pending requests.
while (pending_request != nullptr) {
if (status == GRPC_CREDENTIALS_OK) {
@ -239,42 +243,40 @@ static void on_oauth2_token_fetcher_http_response(void* user_data,
}
GRPC_CLOSURE_SCHED(pending_request->on_request_metadata, error);
grpc_polling_entity_del_from_pollset_set(
pending_request->pollent, grpc_polling_entity_pollset_set(&c->pollent));
pending_request->pollent, grpc_polling_entity_pollset_set(&pollent_));
grpc_oauth2_pending_get_request_metadata* prev = pending_request;
pending_request = pending_request->next;
gpr_free(prev);
}
GRPC_MDELEM_UNREF(access_token_md);
grpc_call_credentials_unref(r->creds);
Unref();
grpc_credentials_metadata_request_destroy(r);
}
static bool oauth2_token_fetcher_get_request_metadata(
grpc_call_credentials* creds, grpc_polling_entity* pollent,
grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata, grpc_error** error) {
grpc_oauth2_token_fetcher_credentials* c =
reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(creds);
bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
// Check if we can use the cached token.
grpc_millis refresh_threshold =
GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS * GPR_MS_PER_SEC;
grpc_mdelem cached_access_token_md = GRPC_MDNULL;
gpr_mu_lock(&c->mu);
if (!GRPC_MDISNULL(c->access_token_md) &&
gpr_mu_lock(&mu_);
if (!GRPC_MDISNULL(access_token_md_) &&
gpr_time_cmp(
gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_MONOTONIC)),
gpr_time_sub(token_expiration_, gpr_now(GPR_CLOCK_MONOTONIC)),
gpr_time_from_seconds(GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
GPR_TIMESPAN)) > 0) {
cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md);
cached_access_token_md = GRPC_MDELEM_REF(access_token_md_);
}
if (!GRPC_MDISNULL(cached_access_token_md)) {
gpr_mu_unlock(&c->mu);
gpr_mu_unlock(&mu_);
grpc_credentials_mdelem_array_add(md_array, cached_access_token_md);
GRPC_MDELEM_UNREF(cached_access_token_md);
return true;
}
// Couldn't get the token from the cache.
// Add request to c->pending_requests and start a new fetch if needed.
// Add request to pending_requests_ and start a new fetch if needed.
grpc_oauth2_pending_get_request_metadata* pending_request =
static_cast<grpc_oauth2_pending_get_request_metadata*>(
gpr_malloc(sizeof(*pending_request)));
@ -282,41 +284,37 @@ static bool oauth2_token_fetcher_get_request_metadata(
pending_request->on_request_metadata = on_request_metadata;
pending_request->pollent = pollent;
grpc_polling_entity_add_to_pollset_set(
pollent, grpc_polling_entity_pollset_set(&c->pollent));
pending_request->next = c->pending_requests;
c->pending_requests = pending_request;
pollent, grpc_polling_entity_pollset_set(&pollent_));
pending_request->next = pending_requests_;
pending_requests_ = pending_request;
bool start_fetch = false;
if (!c->token_fetch_pending) {
c->token_fetch_pending = true;
if (!token_fetch_pending_) {
token_fetch_pending_ = true;
start_fetch = true;
}
gpr_mu_unlock(&c->mu);
gpr_mu_unlock(&mu_);
if (start_fetch) {
grpc_call_credentials_ref(creds);
c->fetch_func(grpc_credentials_metadata_request_create(creds),
&c->httpcli_context, &c->pollent,
on_oauth2_token_fetcher_http_response,
grpc_core::ExecCtx::Get()->Now() + refresh_threshold);
Ref().release();
fetch_oauth2(grpc_credentials_metadata_request_create(this->Ref()),
&httpcli_context_, &pollent_,
on_oauth2_token_fetcher_http_response,
grpc_core::ExecCtx::Get()->Now() + refresh_threshold);
}
return false;
}
static void oauth2_token_fetcher_cancel_get_request_metadata(
grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
grpc_oauth2_token_fetcher_credentials* c =
reinterpret_cast<grpc_oauth2_token_fetcher_credentials*>(creds);
gpr_mu_lock(&c->mu);
void grpc_oauth2_token_fetcher_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
gpr_mu_lock(&mu_);
grpc_oauth2_pending_get_request_metadata* prev = nullptr;
grpc_oauth2_pending_get_request_metadata* pending_request =
c->pending_requests;
grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_;
while (pending_request != nullptr) {
if (pending_request->md_array == md_array) {
// Remove matching pending request from the list.
if (prev != nullptr) {
prev->next = pending_request->next;
} else {
c->pending_requests = pending_request->next;
pending_requests_ = pending_request->next;
}
// Invoke the callback immediately with an error.
GRPC_CLOSURE_SCHED(pending_request->on_request_metadata,
@ -327,96 +325,89 @@ static void oauth2_token_fetcher_cancel_get_request_metadata(
prev = pending_request;
pending_request = pending_request->next;
}
gpr_mu_unlock(&c->mu);
gpr_mu_unlock(&mu_);
GRPC_ERROR_UNREF(error);
}
static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials* c,
grpc_fetch_oauth2_func fetch_func) {
memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
gpr_ref_init(&c->base.refcount, 1);
gpr_mu_init(&c->mu);
c->token_expiration = gpr_inf_past(GPR_CLOCK_MONOTONIC);
c->fetch_func = fetch_func;
c->pollent =
grpc_polling_entity_create_from_pollset_set(grpc_pollset_set_create());
grpc_httpcli_context_init(&c->httpcli_context);
grpc_oauth2_token_fetcher_credentials::grpc_oauth2_token_fetcher_credentials()
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2),
token_expiration_(gpr_inf_past(GPR_CLOCK_MONOTONIC)),
pollent_(grpc_polling_entity_create_from_pollset_set(
grpc_pollset_set_create())) {
gpr_mu_init(&mu_);
grpc_httpcli_context_init(&httpcli_context_);
}
//
// Google Compute Engine credentials.
//
static grpc_call_credentials_vtable compute_engine_vtable = {
oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata,
oauth2_token_fetcher_cancel_get_request_metadata};
namespace {
class grpc_compute_engine_token_fetcher_credentials
: public grpc_oauth2_token_fetcher_credentials {
public:
grpc_compute_engine_token_fetcher_credentials() = default;
~grpc_compute_engine_token_fetcher_credentials() override = default;
protected:
void fetch_oauth2(grpc_credentials_metadata_request* metadata_req,
grpc_httpcli_context* http_context,
grpc_polling_entity* pollent,
grpc_iomgr_cb_func response_cb,
grpc_millis deadline) override {
grpc_http_header header = {(char*)"Metadata-Flavor", (char*)"Google"};
grpc_httpcli_request request;
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = (char*)GRPC_COMPUTE_ENGINE_METADATA_HOST;
request.http.path = (char*)GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
request.http.hdr_count = 1;
request.http.hdrs = &header;
/* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
channel. This would allow us to cancel an authentication query when under
extreme memory pressure. */
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("oauth2_credentials");
grpc_httpcli_get(http_context, pollent, resource_quota, &request, deadline,
GRPC_CLOSURE_CREATE(response_cb, metadata_req,
grpc_schedule_on_exec_ctx),
&metadata_req->response);
grpc_resource_quota_unref_internal(resource_quota);
}
};
static void compute_engine_fetch_oauth2(
grpc_credentials_metadata_request* metadata_req,
grpc_httpcli_context* httpcli_context, grpc_polling_entity* pollent,
grpc_iomgr_cb_func response_cb, grpc_millis deadline) {
grpc_http_header header = {(char*)"Metadata-Flavor", (char*)"Google"};
grpc_httpcli_request request;
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = (char*)GRPC_COMPUTE_ENGINE_METADATA_HOST;
request.http.path = (char*)GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
request.http.hdr_count = 1;
request.http.hdrs = &header;
/* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
channel. This would allow us to cancel an authentication query when under
extreme memory pressure. */
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("oauth2_credentials");
grpc_httpcli_get(
httpcli_context, pollent, resource_quota, &request, deadline,
GRPC_CLOSURE_CREATE(response_cb, metadata_req, grpc_schedule_on_exec_ctx),
&metadata_req->response);
grpc_resource_quota_unref_internal(resource_quota);
}
} // namespace
grpc_call_credentials* grpc_google_compute_engine_credentials_create(
void* reserved) {
grpc_oauth2_token_fetcher_credentials* c =
static_cast<grpc_oauth2_token_fetcher_credentials*>(
gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)));
GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1,
(reserved));
GPR_ASSERT(reserved == nullptr);
init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
c->base.vtable = &compute_engine_vtable;
return &c->base;
return grpc_core::MakeRefCounted<
grpc_compute_engine_token_fetcher_credentials>()
.release();
}
//
// Google Refresh Token credentials.
//
static void refresh_token_destruct(grpc_call_credentials* creds) {
grpc_google_refresh_token_credentials* c =
reinterpret_cast<grpc_google_refresh_token_credentials*>(creds);
grpc_auth_refresh_token_destruct(&c->refresh_token);
oauth2_token_fetcher_destruct(&c->base.base);
grpc_google_refresh_token_credentials::
~grpc_google_refresh_token_credentials() {
grpc_auth_refresh_token_destruct(&refresh_token_);
}
static grpc_call_credentials_vtable refresh_token_vtable = {
refresh_token_destruct, oauth2_token_fetcher_get_request_metadata,
oauth2_token_fetcher_cancel_get_request_metadata};
static void refresh_token_fetch_oauth2(
void grpc_google_refresh_token_credentials::fetch_oauth2(
grpc_credentials_metadata_request* metadata_req,
grpc_httpcli_context* httpcli_context, grpc_polling_entity* pollent,
grpc_iomgr_cb_func response_cb, grpc_millis deadline) {
grpc_google_refresh_token_credentials* c =
reinterpret_cast<grpc_google_refresh_token_credentials*>(
metadata_req->creds);
grpc_http_header header = {(char*)"Content-Type",
(char*)"application/x-www-form-urlencoded"};
grpc_httpcli_request request;
char* body = nullptr;
gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
c->refresh_token.client_id, c->refresh_token.client_secret,
c->refresh_token.refresh_token);
refresh_token_.client_id, refresh_token_.client_secret,
refresh_token_.refresh_token);
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = (char*)GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
request.http.path = (char*)GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
@ -437,20 +428,19 @@ static void refresh_token_fetch_oauth2(
gpr_free(body);
}
grpc_call_credentials*
grpc_google_refresh_token_credentials::grpc_google_refresh_token_credentials(
grpc_auth_refresh_token refresh_token)
: refresh_token_(refresh_token) {}
grpc_core::RefCountedPtr<grpc_call_credentials>
grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token refresh_token) {
grpc_google_refresh_token_credentials* c;
if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
return nullptr;
}
c = static_cast<grpc_google_refresh_token_credentials*>(
gpr_zalloc(sizeof(grpc_google_refresh_token_credentials)));
init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
c->base.base.vtable = &refresh_token_vtable;
c->refresh_token = refresh_token;
return &c->base.base;
return grpc_core::MakeRefCounted<grpc_google_refresh_token_credentials>(
refresh_token);
}
static char* create_loggable_refresh_token(grpc_auth_refresh_token* token) {
@ -478,59 +468,50 @@ grpc_call_credentials* grpc_google_refresh_token_credentials_create(
gpr_free(loggable_token);
}
GPR_ASSERT(reserved == nullptr);
return grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
return grpc_refresh_token_credentials_create_from_auth_refresh_token(token)
.release();
}
//
// Oauth2 Access Token credentials.
//
static void access_token_destruct(grpc_call_credentials* creds) {
grpc_access_token_credentials* c =
reinterpret_cast<grpc_access_token_credentials*>(creds);
GRPC_MDELEM_UNREF(c->access_token_md);
grpc_access_token_credentials::~grpc_access_token_credentials() {
GRPC_MDELEM_UNREF(access_token_md_);
}
static bool access_token_get_request_metadata(
grpc_call_credentials* creds, grpc_polling_entity* pollent,
grpc_auth_metadata_context context, grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata, grpc_error** error) {
grpc_access_token_credentials* c =
reinterpret_cast<grpc_access_token_credentials*>(creds);
grpc_credentials_mdelem_array_add(md_array, c->access_token_md);
bool grpc_access_token_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_credentials_mdelem_array_add(md_array, access_token_md_);
return true;
}
static void access_token_cancel_get_request_metadata(
grpc_call_credentials* c, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
void grpc_access_token_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
static grpc_call_credentials_vtable access_token_vtable = {
access_token_destruct, access_token_get_request_metadata,
access_token_cancel_get_request_metadata};
grpc_access_token_credentials::grpc_access_token_credentials(
const char* access_token)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) {
char* token_md_value;
gpr_asprintf(&token_md_value, "Bearer %s", access_token);
grpc_core::ExecCtx exec_ctx;
access_token_md_ = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY),
grpc_slice_from_copied_string(token_md_value));
gpr_free(token_md_value);
}
grpc_call_credentials* grpc_access_token_credentials_create(
const char* access_token, void* reserved) {
grpc_access_token_credentials* c =
static_cast<grpc_access_token_credentials*>(
gpr_zalloc(sizeof(grpc_access_token_credentials)));
GRPC_API_TRACE(
"grpc_access_token_credentials_create(access_token=<redacted>, "
"reserved=%p)",
1, (reserved));
GPR_ASSERT(reserved == nullptr);
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
c->base.vtable = &access_token_vtable;
gpr_ref_init(&c->base.refcount, 1);
char* token_md_value;
gpr_asprintf(&token_md_value, "Bearer %s", access_token);
grpc_core::ExecCtx exec_ctx;
c->access_token_md = grpc_mdelem_from_slices(
grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY),
grpc_slice_from_copied_string(token_md_value));
gpr_free(token_md_value);
return &c->base;
return grpc_core::MakeRefCounted<grpc_access_token_credentials>(access_token)
.release();
}

@ -54,46 +54,91 @@ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token* refresh_token);
// This object is a base for credentials that need to acquire an oauth2 token
// from an http service.
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request* req,
grpc_httpcli_context* http_context,
grpc_polling_entity* pollent,
grpc_iomgr_cb_func cb,
grpc_millis deadline);
typedef struct grpc_oauth2_pending_get_request_metadata {
struct grpc_oauth2_pending_get_request_metadata {
grpc_credentials_mdelem_array* md_array;
grpc_closure* on_request_metadata;
grpc_polling_entity* pollent;
struct grpc_oauth2_pending_get_request_metadata* next;
} grpc_oauth2_pending_get_request_metadata;
typedef struct {
grpc_call_credentials base;
gpr_mu mu;
grpc_mdelem access_token_md;
gpr_timespec token_expiration;
bool token_fetch_pending;
grpc_oauth2_pending_get_request_metadata* pending_requests;
grpc_httpcli_context httpcli_context;
grpc_fetch_oauth2_func fetch_func;
grpc_polling_entity pollent;
} grpc_oauth2_token_fetcher_credentials;
};
class grpc_oauth2_token_fetcher_credentials : public grpc_call_credentials {
public:
grpc_oauth2_token_fetcher_credentials();
~grpc_oauth2_token_fetcher_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
void on_http_response(grpc_credentials_metadata_request* r,
grpc_error* error);
GRPC_ABSTRACT_BASE_CLASS
protected:
virtual void fetch_oauth2(grpc_credentials_metadata_request* req,
grpc_httpcli_context* httpcli_context,
grpc_polling_entity* pollent, grpc_iomgr_cb_func cb,
grpc_millis deadline) GRPC_ABSTRACT;
private:
gpr_mu mu_;
grpc_mdelem access_token_md_ = GRPC_MDNULL;
gpr_timespec token_expiration_;
bool token_fetch_pending_ = false;
grpc_oauth2_pending_get_request_metadata* pending_requests_ = nullptr;
grpc_httpcli_context httpcli_context_;
grpc_polling_entity pollent_;
};
// Google refresh token credentials.
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
} grpc_google_refresh_token_credentials;
class grpc_google_refresh_token_credentials final
: public grpc_oauth2_token_fetcher_credentials {
public:
grpc_google_refresh_token_credentials(grpc_auth_refresh_token refresh_token);
~grpc_google_refresh_token_credentials() override;
const grpc_auth_refresh_token& refresh_token() const {
return refresh_token_;
}
protected:
void fetch_oauth2(grpc_credentials_metadata_request* req,
grpc_httpcli_context* httpcli_context,
grpc_polling_entity* pollent, grpc_iomgr_cb_func cb,
grpc_millis deadline) override;
private:
grpc_auth_refresh_token refresh_token_;
};
// Access token credentials.
typedef struct {
grpc_call_credentials base;
grpc_mdelem access_token_md;
} grpc_access_token_credentials;
class grpc_access_token_credentials final : public grpc_call_credentials {
public:
grpc_access_token_credentials(const char* access_token);
~grpc_access_token_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
private:
grpc_mdelem access_token_md_;
};
// Private constructor for refresh token credentials from an already parsed
// refresh token. Takes ownership of the refresh token.
grpc_call_credentials*
grpc_core::RefCountedPtr<grpc_call_credentials>
grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token token);

@ -35,20 +35,17 @@
grpc_core::TraceFlag grpc_plugin_credentials_trace(false, "plugin_credentials");
static void plugin_destruct(grpc_call_credentials* creds) {
grpc_plugin_credentials* c =
reinterpret_cast<grpc_plugin_credentials*>(creds);
gpr_mu_destroy(&c->mu);
if (c->plugin.state != nullptr && c->plugin.destroy != nullptr) {
c->plugin.destroy(c->plugin.state);
grpc_plugin_credentials::~grpc_plugin_credentials() {
gpr_mu_destroy(&mu_);
if (plugin_.state != nullptr && plugin_.destroy != nullptr) {
plugin_.destroy(plugin_.state);
}
}
static void pending_request_remove_locked(
grpc_plugin_credentials* c,
grpc_plugin_credentials_pending_request* pending_request) {
void grpc_plugin_credentials::pending_request_remove_locked(
pending_request* pending_request) {
if (pending_request->prev == nullptr) {
c->pending_requests = pending_request->next;
pending_requests_ = pending_request->next;
} else {
pending_request->prev->next = pending_request->next;
}
@ -62,17 +59,17 @@ static void pending_request_remove_locked(
// cancelled out from under us.
// When this returns, r->cancelled indicates whether the request was
// cancelled before completion.
static void pending_request_complete(
grpc_plugin_credentials_pending_request* r) {
gpr_mu_lock(&r->creds->mu);
if (!r->cancelled) pending_request_remove_locked(r->creds, r);
gpr_mu_unlock(&r->creds->mu);
void grpc_plugin_credentials::pending_request_complete(pending_request* r) {
GPR_DEBUG_ASSERT(r->creds == this);
gpr_mu_lock(&mu_);
if (!r->cancelled) pending_request_remove_locked(r);
gpr_mu_unlock(&mu_);
// Ref to credentials not needed anymore.
grpc_call_credentials_unref(&r->creds->base);
Unref();
}
static grpc_error* process_plugin_result(
grpc_plugin_credentials_pending_request* r, const grpc_metadata* md,
grpc_plugin_credentials::pending_request* r, const grpc_metadata* md,
size_t num_md, grpc_status_code status, const char* error_details) {
grpc_error* error = GRPC_ERROR_NONE;
if (status != GRPC_STATUS_OK) {
@ -119,8 +116,8 @@ static void plugin_md_request_metadata_ready(void* request,
/* called from application code */
grpc_core::ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_FINISHED |
GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP);
grpc_plugin_credentials_pending_request* r =
static_cast<grpc_plugin_credentials_pending_request*>(request);
grpc_plugin_credentials::pending_request* r =
static_cast<grpc_plugin_credentials::pending_request*>(request);
if (grpc_plugin_credentials_trace.enabled()) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
@ -128,7 +125,7 @@ static void plugin_md_request_metadata_ready(void* request,
r->creds, r);
}
// Remove request from pending list if not previously cancelled.
pending_request_complete(r);
r->creds->pending_request_complete(r);
// If it has not been cancelled, process it.
if (!r->cancelled) {
grpc_error* error =
@ -143,65 +140,59 @@ static void plugin_md_request_metadata_ready(void* request,
gpr_free(r);
}
static bool plugin_get_request_metadata(grpc_call_credentials* creds,
grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) {
grpc_plugin_credentials* c =
reinterpret_cast<grpc_plugin_credentials*>(creds);
bool grpc_plugin_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
grpc_error** error) {
bool retval = true; // Synchronous return.
if (c->plugin.get_metadata != nullptr) {
if (plugin_.get_metadata != nullptr) {
// Create pending_request object.
grpc_plugin_credentials_pending_request* pending_request =
static_cast<grpc_plugin_credentials_pending_request*>(
gpr_zalloc(sizeof(*pending_request)));
pending_request->creds = c;
pending_request->md_array = md_array;
pending_request->on_request_metadata = on_request_metadata;
pending_request* request =
static_cast<pending_request*>(gpr_zalloc(sizeof(*request)));
request->creds = this;
request->md_array = md_array;
request->on_request_metadata = on_request_metadata;
// Add it to the pending list.
gpr_mu_lock(&c->mu);
if (c->pending_requests != nullptr) {
c->pending_requests->prev = pending_request;
gpr_mu_lock(&mu_);
if (pending_requests_ != nullptr) {
pending_requests_->prev = request;
}
pending_request->next = c->pending_requests;
c->pending_requests = pending_request;
gpr_mu_unlock(&c->mu);
request->next = pending_requests_;
pending_requests_ = request;
gpr_mu_unlock(&mu_);
// Invoke the plugin. The callback holds a ref to us.
if (grpc_plugin_credentials_trace.enabled()) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin",
c, pending_request);
this, request);
}
grpc_call_credentials_ref(creds);
Ref().release();
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX];
size_t num_creds_md = 0;
grpc_status_code status = GRPC_STATUS_OK;
const char* error_details = nullptr;
if (!c->plugin.get_metadata(c->plugin.state, context,
plugin_md_request_metadata_ready,
pending_request, creds_md, &num_creds_md,
&status, &error_details)) {
if (!plugin_.get_metadata(
plugin_.state, context, plugin_md_request_metadata_ready, request,
creds_md, &num_creds_md, &status, &error_details)) {
if (grpc_plugin_credentials_trace.enabled()) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin will return "
"asynchronously",
c, pending_request);
this, request);
}
return false; // Asynchronous return.
}
// Returned synchronously.
// Remove request from pending list if not previously cancelled.
pending_request_complete(pending_request);
request->creds->pending_request_complete(request);
// If the request was cancelled, the error will have been returned
// asynchronously by plugin_cancel_get_request_metadata(), so return
// false. Otherwise, process the result.
if (pending_request->cancelled) {
if (request->cancelled) {
if (grpc_plugin_credentials_trace.enabled()) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p was cancelled, error "
"will be returned asynchronously",
c, pending_request);
this, request);
}
retval = false;
} else {
@ -209,10 +200,10 @@ static bool plugin_get_request_metadata(grpc_call_credentials* creds,
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
"synchronously",
c, pending_request);
this, request);
}
*error = process_plugin_result(pending_request, creds_md, num_creds_md,
status, error_details);
*error = process_plugin_result(request, creds_md, num_creds_md, status,
error_details);
}
// Clean up.
for (size_t i = 0; i < num_creds_md; ++i) {
@ -220,51 +211,42 @@ static bool plugin_get_request_metadata(grpc_call_credentials* creds,
grpc_slice_unref_internal(creds_md[i].value);
}
gpr_free((void*)error_details);
gpr_free(pending_request);
gpr_free(request);
}
return retval;
}
static void plugin_cancel_get_request_metadata(
grpc_call_credentials* creds, grpc_credentials_mdelem_array* md_array,
grpc_error* error) {
grpc_plugin_credentials* c =
reinterpret_cast<grpc_plugin_credentials*>(creds);
gpr_mu_lock(&c->mu);
for (grpc_plugin_credentials_pending_request* pending_request =
c->pending_requests;
void grpc_plugin_credentials::cancel_get_request_metadata(
grpc_credentials_mdelem_array* md_array, grpc_error* error) {
gpr_mu_lock(&mu_);
for (pending_request* pending_request = pending_requests_;
pending_request != nullptr; pending_request = pending_request->next) {
if (pending_request->md_array == md_array) {
if (grpc_plugin_credentials_trace.enabled()) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", c,
gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", this,
pending_request);
}
pending_request->cancelled = true;
GRPC_CLOSURE_SCHED(pending_request->on_request_metadata,
GRPC_ERROR_REF(error));
pending_request_remove_locked(c, pending_request);
pending_request_remove_locked(pending_request);
break;
}
}
gpr_mu_unlock(&c->mu);
gpr_mu_unlock(&mu_);
GRPC_ERROR_UNREF(error);
}
static grpc_call_credentials_vtable plugin_vtable = {
plugin_destruct, plugin_get_request_metadata,
plugin_cancel_get_request_metadata};
grpc_plugin_credentials::grpc_plugin_credentials(
grpc_metadata_credentials_plugin plugin)
: grpc_call_credentials(plugin.type), plugin_(plugin) {
gpr_mu_init(&mu_);
}
grpc_call_credentials* grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin, void* reserved) {
grpc_plugin_credentials* c =
static_cast<grpc_plugin_credentials*>(gpr_zalloc(sizeof(*c)));
GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1,
(reserved));
GPR_ASSERT(reserved == nullptr);
c->base.type = plugin.type;
c->base.vtable = &plugin_vtable;
gpr_ref_init(&c->base.refcount, 1);
c->plugin = plugin;
gpr_mu_init(&c->mu);
return &c->base;
return grpc_core::New<grpc_plugin_credentials>(plugin);
}

@ -25,22 +25,45 @@
extern grpc_core::TraceFlag grpc_plugin_credentials_trace;
struct grpc_plugin_credentials;
typedef struct grpc_plugin_credentials_pending_request {
bool cancelled;
struct grpc_plugin_credentials* creds;
grpc_credentials_mdelem_array* md_array;
grpc_closure* on_request_metadata;
struct grpc_plugin_credentials_pending_request* prev;
struct grpc_plugin_credentials_pending_request* next;
} grpc_plugin_credentials_pending_request;
typedef struct grpc_plugin_credentials {
grpc_call_credentials base;
grpc_metadata_credentials_plugin plugin;
gpr_mu mu;
grpc_plugin_credentials_pending_request* pending_requests;
} grpc_plugin_credentials;
// This type is forward declared as a C struct and we cannot define it as a
// class. Otherwise, compiler will complain about type mismatch due to
// -Wmismatched-tags.
struct grpc_plugin_credentials final : public grpc_call_credentials {
public:
struct pending_request {
bool cancelled;
struct grpc_plugin_credentials* creds;
grpc_credentials_mdelem_array* md_array;
grpc_closure* on_request_metadata;
struct pending_request* prev;
struct pending_request* next;
};
explicit grpc_plugin_credentials(grpc_metadata_credentials_plugin plugin);
~grpc_plugin_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_credentials_mdelem_array* md_array,
grpc_closure* on_request_metadata,
grpc_error** error) override;
void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array,
grpc_error* error) override;
// Checks if the request has been cancelled.
// If not, removes it from the pending list, so that it cannot be
// cancelled out from under us.
// When this returns, r->cancelled indicates whether the request was
// cancelled before completion.
void pending_request_complete(pending_request* r);
private:
void pending_request_remove_locked(pending_request* pending_request);
grpc_metadata_credentials_plugin plugin_;
gpr_mu mu_;
pending_request* pending_requests_ = nullptr;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H */

@ -44,22 +44,27 @@ void grpc_tsi_ssl_pem_key_cert_pairs_destroy(tsi_ssl_pem_key_cert_pair* kp,
gpr_free(kp);
}
static void ssl_destruct(grpc_channel_credentials* creds) {
grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
gpr_free(c->config.pem_root_certs);
grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pair, 1);
if (c->config.verify_options.verify_peer_destruct != nullptr) {
c->config.verify_options.verify_peer_destruct(
c->config.verify_options.verify_peer_callback_userdata);
grpc_ssl_credentials::grpc_ssl_credentials(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options)
: grpc_channel_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_SSL) {
build_config(pem_root_certs, pem_key_cert_pair, verify_options);
}
grpc_ssl_credentials::~grpc_ssl_credentials() {
gpr_free(config_.pem_root_certs);
grpc_tsi_ssl_pem_key_cert_pairs_destroy(config_.pem_key_cert_pair, 1);
if (config_.verify_options.verify_peer_destruct != nullptr) {
config_.verify_options.verify_peer_destruct(
config_.verify_options.verify_peer_callback_userdata);
}
}
static grpc_security_status ssl_create_security_connector(
grpc_channel_credentials* creds, grpc_call_credentials* call_creds,
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_ssl_credentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
grpc_ssl_credentials* c = reinterpret_cast<grpc_ssl_credentials*>(creds);
grpc_security_status status = GRPC_SECURITY_OK;
grpc_channel_args** new_args) {
const char* overridden_target_name = nullptr;
tsi_ssl_session_cache* ssl_session_cache = nullptr;
for (size_t i = 0; args && i < args->num_args; i++) {
@ -74,52 +79,47 @@ static grpc_security_status ssl_create_security_connector(
static_cast<tsi_ssl_session_cache*>(arg->value.pointer.p);
}
}
status = grpc_ssl_channel_security_connector_create(
creds, call_creds, &c->config, target, overridden_target_name,
ssl_session_cache, sc);
if (status != GRPC_SECURITY_OK) {
return status;
grpc_core::RefCountedPtr<grpc_channel_security_connector> sc =
grpc_ssl_channel_security_connector_create(
this->Ref(), std::move(call_creds), &config_, target,
overridden_target_name, ssl_session_cache);
if (sc == nullptr) {
return sc;
}
grpc_arg new_arg = grpc_channel_arg_string_create(
(char*)GRPC_ARG_HTTP2_SCHEME, (char*)"https");
*new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1);
return status;
return sc;
}
static grpc_channel_credentials_vtable ssl_vtable = {
ssl_destruct, ssl_create_security_connector, nullptr};
static void ssl_build_config(const char* pem_root_certs,
grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options,
grpc_ssl_config* config) {
if (pem_root_certs != nullptr) {
config->pem_root_certs = gpr_strdup(pem_root_certs);
}
void grpc_ssl_credentials::build_config(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options) {
config_.pem_root_certs = gpr_strdup(pem_root_certs);
if (pem_key_cert_pair != nullptr) {
GPR_ASSERT(pem_key_cert_pair->private_key != nullptr);
GPR_ASSERT(pem_key_cert_pair->cert_chain != nullptr);
config->pem_key_cert_pair = static_cast<tsi_ssl_pem_key_cert_pair*>(
config_.pem_key_cert_pair = static_cast<tsi_ssl_pem_key_cert_pair*>(
gpr_zalloc(sizeof(tsi_ssl_pem_key_cert_pair)));
config->pem_key_cert_pair->cert_chain =
config_.pem_key_cert_pair->cert_chain =
gpr_strdup(pem_key_cert_pair->cert_chain);
config->pem_key_cert_pair->private_key =
config_.pem_key_cert_pair->private_key =
gpr_strdup(pem_key_cert_pair->private_key);
} else {
config_.pem_key_cert_pair = nullptr;
}
if (verify_options != nullptr) {
memcpy(&config->verify_options, verify_options,
memcpy(&config_.verify_options, verify_options,
sizeof(verify_peer_options));
} else {
// Otherwise set all options to default values
memset(&config->verify_options, 0, sizeof(verify_peer_options));
memset(&config_.verify_options, 0, sizeof(verify_peer_options));
}
}
grpc_channel_credentials* grpc_ssl_credentials_create(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options, void* reserved) {
grpc_ssl_credentials* c = static_cast<grpc_ssl_credentials*>(
gpr_zalloc(sizeof(grpc_ssl_credentials)));
GRPC_API_TRACE(
"grpc_ssl_credentials_create(pem_root_certs=%s, "
"pem_key_cert_pair=%p, "
@ -127,12 +127,9 @@ grpc_channel_credentials* grpc_ssl_credentials_create(
"reserved=%p)",
4, (pem_root_certs, pem_key_cert_pair, verify_options, reserved));
GPR_ASSERT(reserved == nullptr);
c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
c->base.vtable = &ssl_vtable;
gpr_ref_init(&c->base.refcount, 1);
ssl_build_config(pem_root_certs, pem_key_cert_pair, verify_options,
&c->config);
return &c->base;
return grpc_core::New<grpc_ssl_credentials>(pem_root_certs, pem_key_cert_pair,
verify_options);
}
//
@ -145,21 +142,29 @@ struct grpc_ssl_server_credentials_options {
grpc_ssl_server_certificate_config_fetcher* certificate_config_fetcher;
};
static void ssl_server_destruct(grpc_server_credentials* creds) {
grpc_ssl_server_credentials* c =
reinterpret_cast<grpc_ssl_server_credentials*>(creds);
grpc_tsi_ssl_pem_key_cert_pairs_destroy(c->config.pem_key_cert_pairs,
c->config.num_key_cert_pairs);
gpr_free(c->config.pem_root_certs);
grpc_ssl_server_credentials::grpc_ssl_server_credentials(
const grpc_ssl_server_credentials_options& options)
: grpc_server_credentials(GRPC_CHANNEL_CREDENTIALS_TYPE_SSL) {
if (options.certificate_config_fetcher != nullptr) {
config_.client_certificate_request = options.client_certificate_request;
certificate_config_fetcher_ = *options.certificate_config_fetcher;
} else {
build_config(options.certificate_config->pem_root_certs,
options.certificate_config->pem_key_cert_pairs,
options.certificate_config->num_key_cert_pairs,
options.client_certificate_request);
}
}
static grpc_security_status ssl_server_create_security_connector(
grpc_server_credentials* creds, grpc_server_security_connector** sc) {
return grpc_ssl_server_security_connector_create(creds, sc);
grpc_ssl_server_credentials::~grpc_ssl_server_credentials() {
grpc_tsi_ssl_pem_key_cert_pairs_destroy(config_.pem_key_cert_pairs,
config_.num_key_cert_pairs);
gpr_free(config_.pem_root_certs);
}
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_ssl_server_credentials::create_security_connector() {
return grpc_ssl_server_security_connector_create(this->Ref());
}
static grpc_server_credentials_vtable ssl_server_vtable = {
ssl_server_destruct, ssl_server_create_security_connector};
tsi_ssl_pem_key_cert_pair* grpc_convert_grpc_to_tsi_cert_pairs(
const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,
@ -179,18 +184,15 @@ tsi_ssl_pem_key_cert_pair* grpc_convert_grpc_to_tsi_cert_pairs(
return tsi_pairs;
}
static void ssl_build_server_config(
void grpc_ssl_server_credentials::build_config(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,
size_t num_key_cert_pairs,
grpc_ssl_client_certificate_request_type client_certificate_request,
grpc_ssl_server_config* config) {
config->client_certificate_request = client_certificate_request;
if (pem_root_certs != nullptr) {
config->pem_root_certs = gpr_strdup(pem_root_certs);
}
config->pem_key_cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
grpc_ssl_client_certificate_request_type client_certificate_request) {
config_.client_certificate_request = client_certificate_request;
config_.pem_root_certs = gpr_strdup(pem_root_certs);
config_.pem_key_cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
pem_key_cert_pairs, num_key_cert_pairs);
config->num_key_cert_pairs = num_key_cert_pairs;
config_.num_key_cert_pairs = num_key_cert_pairs;
}
grpc_ssl_server_certificate_config* grpc_ssl_server_certificate_config_create(
@ -200,9 +202,7 @@ grpc_ssl_server_certificate_config* grpc_ssl_server_certificate_config_create(
grpc_ssl_server_certificate_config* config =
static_cast<grpc_ssl_server_certificate_config*>(
gpr_zalloc(sizeof(grpc_ssl_server_certificate_config)));
if (pem_root_certs != nullptr) {
config->pem_root_certs = gpr_strdup(pem_root_certs);
}
config->pem_root_certs = gpr_strdup(pem_root_certs);
if (num_key_cert_pairs > 0) {
GPR_ASSERT(pem_key_cert_pairs != nullptr);
config->pem_key_cert_pairs = static_cast<grpc_ssl_pem_key_cert_pair*>(
@ -311,7 +311,6 @@ grpc_server_credentials* grpc_ssl_server_credentials_create_ex(
grpc_server_credentials* grpc_ssl_server_credentials_create_with_options(
grpc_ssl_server_credentials_options* options) {
grpc_server_credentials* retval = nullptr;
grpc_ssl_server_credentials* c = nullptr;
if (options == nullptr) {
gpr_log(GPR_ERROR,
@ -331,23 +330,7 @@ grpc_server_credentials* grpc_ssl_server_credentials_create_with_options(
goto done;
}
c = static_cast<grpc_ssl_server_credentials*>(
gpr_zalloc(sizeof(grpc_ssl_server_credentials)));
c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &ssl_server_vtable;
if (options->certificate_config_fetcher != nullptr) {
c->config.client_certificate_request = options->client_certificate_request;
c->certificate_config_fetcher = *options->certificate_config_fetcher;
} else {
ssl_build_server_config(options->certificate_config->pem_root_certs,
options->certificate_config->pem_key_cert_pairs,
options->certificate_config->num_key_cert_pairs,
options->client_certificate_request, &c->config);
}
retval = &c->base;
retval = grpc_core::New<grpc_ssl_server_credentials>(*options);
done:
grpc_ssl_server_credentials_options_destroy(options);

@ -24,27 +24,70 @@
#include "src/core/lib/security/security_connector/ssl/ssl_security_connector.h"
typedef struct {
grpc_channel_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
class grpc_ssl_credentials : public grpc_channel_credentials {
public:
grpc_ssl_credentials(const char* pem_root_certs,
grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options);
~grpc_ssl_credentials() override;
grpc_core::RefCountedPtr<grpc_channel_security_connector>
create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target, const grpc_channel_args* args,
grpc_channel_args** new_args) override;
private:
void build_config(const char* pem_root_certs,
grpc_ssl_pem_key_cert_pair* pem_key_cert_pair,
const verify_peer_options* verify_options);
grpc_ssl_config config_;
};
struct grpc_ssl_server_certificate_config {
grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs;
size_t num_key_cert_pairs;
char* pem_root_certs;
grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr;
size_t num_key_cert_pairs = 0;
char* pem_root_certs = nullptr;
};
typedef struct {
grpc_ssl_server_certificate_config_callback cb;
struct grpc_ssl_server_certificate_config_fetcher {
grpc_ssl_server_certificate_config_callback cb = nullptr;
void* user_data;
} grpc_ssl_server_certificate_config_fetcher;
};
class grpc_ssl_server_credentials final : public grpc_server_credentials {
public:
grpc_ssl_server_credentials(
const grpc_ssl_server_credentials_options& options);
~grpc_ssl_server_credentials() override;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
grpc_ssl_server_certificate_config_fetcher certificate_config_fetcher;
} grpc_ssl_server_credentials;
grpc_core::RefCountedPtr<grpc_server_security_connector>
create_security_connector() override;
bool has_cert_config_fetcher() const {
return certificate_config_fetcher_.cb != nullptr;
}
grpc_ssl_certificate_config_reload_status FetchCertConfig(
grpc_ssl_server_certificate_config** config) {
GPR_DEBUG_ASSERT(has_cert_config_fetcher());
return certificate_config_fetcher_.cb(certificate_config_fetcher_.user_data,
config);
}
const grpc_ssl_server_config& config() const { return config_; }
private:
void build_config(
const char* pem_root_certs,
grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, size_t num_key_cert_pairs,
grpc_ssl_client_certificate_request_type client_certificate_request);
grpc_ssl_server_config config_;
grpc_ssl_server_certificate_config_fetcher certificate_config_fetcher_;
};
tsi_ssl_pem_key_cert_pair* grpc_convert_grpc_to_tsi_cert_pairs(
const grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,

@ -28,6 +28,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/credentials/alts/alts_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
@ -35,64 +36,9 @@
#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
#include "src/core/tsi/transport_security.h"
typedef struct {
grpc_channel_security_connector base;
char* target_name;
} grpc_alts_channel_security_connector;
namespace {
typedef struct {
grpc_server_security_connector base;
} grpc_alts_server_security_connector;
static void alts_channel_destroy(grpc_security_connector* sc) {
if (sc == nullptr) {
return;
}
auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
grpc_call_credentials_unref(c->base.request_metadata_creds);
grpc_channel_credentials_unref(c->base.channel_creds);
gpr_free(c->target_name);
gpr_free(sc);
}
static void alts_server_destroy(grpc_security_connector* sc) {
if (sc == nullptr) {
return;
}
auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
grpc_server_credentials_unref(c->base.server_creds);
gpr_free(sc);
}
static void alts_channel_add_handshakers(
grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
grpc_alts_credentials* creds =
reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
GPR_ASSERT(alts_tsi_handshaker_create(
creds->options, c->target_name, creds->handshaker_service_url,
true, interested_parties, &handshaker) == TSI_OK);
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
handshaker, &sc->base));
}
static void alts_server_add_handshakers(
grpc_server_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
grpc_alts_server_credentials* creds =
reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
GPR_ASSERT(alts_tsi_handshaker_create(
creds->options, nullptr, creds->handshaker_service_url, false,
interested_parties, &handshaker) == TSI_OK);
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
handshaker, &sc->base));
}
static void alts_set_rpc_protocol_versions(
void alts_set_rpc_protocol_versions(
grpc_gcp_rpc_protocol_versions* rpc_versions) {
grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
GRPC_PROTOCOL_VERSION_MAX_MAJOR,
@ -102,17 +48,131 @@ static void alts_set_rpc_protocol_versions(
GRPC_PROTOCOL_VERSION_MIN_MINOR);
}
void alts_check_peer(tsi_peer peer,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) {
*auth_context =
grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer);
tsi_peer_destruct(&peer);
grpc_error* error =
*auth_context != nullptr
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Could not get ALTS auth context from TSI peer");
GRPC_CLOSURE_SCHED(on_peer_checked, error);
}
class grpc_alts_channel_security_connector final
: public grpc_channel_security_connector {
public:
grpc_alts_channel_security_connector(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name)
: grpc_channel_security_connector(/*url_scheme=*/nullptr,
std::move(channel_creds),
std::move(request_metadata_creds)),
target_name_(gpr_strdup(target_name)) {
grpc_alts_credentials* creds =
static_cast<grpc_alts_credentials*>(mutable_channel_creds());
alts_set_rpc_protocol_versions(&creds->mutable_options()->rpc_versions);
}
~grpc_alts_channel_security_connector() override { gpr_free(target_name_); }
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) override {
tsi_handshaker* handshaker = nullptr;
const grpc_alts_credentials* creds =
static_cast<const grpc_alts_credentials*>(channel_creds());
GPR_ASSERT(alts_tsi_handshaker_create(creds->options(), target_name_,
creds->handshaker_service_url(), true,
interested_parties,
&handshaker) == TSI_OK);
grpc_handshake_manager_add(
handshake_manager, grpc_security_handshaker_create(handshaker, this));
}
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
alts_check_peer(peer, auth_context, on_peer_checked);
}
int cmp(const grpc_security_connector* other_sc) const override {
auto* other =
reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
int c = channel_security_connector_cmp(other);
if (c != 0) return c;
return strcmp(target_name_, other->target_name_);
}
bool check_call_host(const char* host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) override {
if (host == nullptr || strcmp(host, target_name_) != 0) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"ALTS call host does not match target name");
}
return true;
}
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error* error) override {
GRPC_ERROR_UNREF(error);
}
private:
char* target_name_;
};
class grpc_alts_server_security_connector final
: public grpc_server_security_connector {
public:
grpc_alts_server_security_connector(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_server_security_connector(/*url_scheme=*/nullptr,
std::move(server_creds)) {
grpc_alts_server_credentials* creds =
reinterpret_cast<grpc_alts_server_credentials*>(mutable_server_creds());
alts_set_rpc_protocol_versions(&creds->mutable_options()->rpc_versions);
}
~grpc_alts_server_security_connector() override = default;
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) override {
tsi_handshaker* handshaker = nullptr;
const grpc_alts_server_credentials* creds =
static_cast<const grpc_alts_server_credentials*>(server_creds());
GPR_ASSERT(alts_tsi_handshaker_create(
creds->options(), nullptr, creds->handshaker_service_url(),
false, interested_parties, &handshaker) == TSI_OK);
grpc_handshake_manager_add(
handshake_manager, grpc_security_handshaker_create(handshaker, this));
}
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
alts_check_peer(peer, auth_context, on_peer_checked);
}
int cmp(const grpc_security_connector* other) const override {
return server_security_connector_cmp(
static_cast<const grpc_server_security_connector*>(other));
}
};
} // namespace
namespace grpc_core {
namespace internal {
grpc_security_status grpc_alts_auth_context_from_tsi_peer(
const tsi_peer* peer, grpc_auth_context** ctx) {
if (peer == nullptr || ctx == nullptr) {
grpc_core::RefCountedPtr<grpc_auth_context>
grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) {
if (peer == nullptr) {
gpr_log(GPR_ERROR,
"Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
return GRPC_SECURITY_ERROR;
return nullptr;
}
*ctx = nullptr;
/* Validate certificate type. */
const tsi_peer_property* cert_type_prop =
tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
@ -120,14 +180,14 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer(
strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
cert_type_prop->value.length) != 0) {
gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
return GRPC_SECURITY_ERROR;
return nullptr;
}
/* Validate RPC protocol versions. */
const tsi_peer_property* rpc_versions_prop =
tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
if (rpc_versions_prop == nullptr) {
gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
return GRPC_SECURITY_ERROR;
return nullptr;
}
grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
alts_set_rpc_protocol_versions(&local_versions);
@ -138,19 +198,19 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer(
grpc_slice_unref_internal(slice);
if (!decode_result) {
gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
return GRPC_SECURITY_ERROR;
return nullptr;
}
/* TODO: Pass highest common rpc protocol version to grpc caller. */
bool check_result = grpc_gcp_rpc_protocol_versions_check(
&local_versions, &peer_versions, nullptr);
if (!check_result) {
gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
return GRPC_SECURITY_ERROR;
return nullptr;
}
/* Create auth context. */
*ctx = grpc_auth_context_create(nullptr);
auto ctx = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
grpc_auth_context_add_cstring_property(
*ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
size_t i = 0;
for (i = 0; i < peer->property_count; i++) {
@ -158,132 +218,47 @@ grpc_security_status grpc_alts_auth_context_from_tsi_peer(
/* Add service account to auth context. */
if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(
*ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, tsi_prop->value.data,
tsi_prop->value.length);
ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY,
tsi_prop->value.data, tsi_prop->value.length);
GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
*ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
}
}
if (!grpc_auth_context_peer_is_authenticated(*ctx)) {
if (!grpc_auth_context_peer_is_authenticated(ctx.get())) {
gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
GRPC_AUTH_CONTEXT_UNREF(*ctx, "test");
*ctx = nullptr;
return GRPC_SECURITY_ERROR;
ctx.reset(DEBUG_LOCATION, "test");
return nullptr;
}
return GRPC_SECURITY_OK;
return ctx;
}
} // namespace internal
} // namespace grpc_core
static void alts_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
grpc_security_status status;
status = grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(
&peer, auth_context);
tsi_peer_destruct(&peer);
grpc_error* error =
status == GRPC_SECURITY_OK
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Could not get ALTS auth context from TSI peer");
GRPC_CLOSURE_SCHED(on_peer_checked, error);
}
static int alts_channel_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_alts_channel_security_connector* c1 =
reinterpret_cast<grpc_alts_channel_security_connector*>(sc1);
grpc_alts_channel_security_connector* c2 =
reinterpret_cast<grpc_alts_channel_security_connector*>(sc2);
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
if (c != 0) return c;
return strcmp(c1->target_name, c2->target_name);
}
static int alts_server_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_alts_server_security_connector* c1 =
reinterpret_cast<grpc_alts_server_security_connector*>(sc1);
grpc_alts_server_security_connector* c2 =
reinterpret_cast<grpc_alts_server_security_connector*>(sc2);
return grpc_server_security_connector_cmp(&c1->base, &c2->base);
}
static grpc_security_connector_vtable alts_channel_vtable = {
alts_channel_destroy, alts_check_peer, alts_channel_cmp};
static grpc_security_connector_vtable alts_server_vtable = {
alts_server_destroy, alts_check_peer, alts_server_cmp};
static bool alts_check_call_host(grpc_channel_security_connector* sc,
const char* host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) {
grpc_alts_channel_security_connector* alts_sc =
reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
if (host == nullptr || alts_sc == nullptr ||
strcmp(host, alts_sc->target_name) != 0) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"ALTS call host does not match target name");
}
return true;
}
static void alts_cancel_check_call_host(grpc_channel_security_connector* sc,
grpc_closure* on_call_host_checked,
grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
grpc_security_status grpc_alts_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds, const char* target_name,
grpc_channel_security_connector** sc) {
if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) {
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_alts_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name) {
if (channel_creds == nullptr || target_name == nullptr) {
gpr_log(
GPR_ERROR,
"Invalid arguments to grpc_alts_channel_security_connector_create()");
return GRPC_SECURITY_ERROR;
return nullptr;
}
auto c = static_cast<grpc_alts_channel_security_connector*>(
gpr_zalloc(sizeof(grpc_alts_channel_security_connector)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &alts_channel_vtable;
c->base.add_handshakers = alts_channel_add_handshakers;
c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = alts_check_call_host;
c->base.cancel_check_call_host = alts_cancel_check_call_host;
grpc_alts_credentials* creds =
reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
c->target_name = gpr_strdup(target_name);
*sc = &c->base;
return GRPC_SECURITY_OK;
return grpc_core::MakeRefCounted<grpc_alts_channel_security_connector>(
std::move(channel_creds), std::move(request_metadata_creds), target_name);
}
grpc_security_status grpc_alts_server_security_connector_create(
grpc_server_credentials* server_creds,
grpc_server_security_connector** sc) {
if (server_creds == nullptr || sc == nullptr) {
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
if (server_creds == nullptr) {
gpr_log(
GPR_ERROR,
"Invalid arguments to grpc_alts_server_security_connector_create()");
return GRPC_SECURITY_ERROR;
return nullptr;
}
auto c = static_cast<grpc_alts_server_security_connector*>(
gpr_zalloc(sizeof(grpc_alts_server_security_connector)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &alts_server_vtable;
c->base.server_creds = grpc_server_credentials_ref(server_creds);
c->base.add_handshakers = alts_server_add_handshakers;
grpc_alts_server_credentials* creds =
reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
*sc = &c->base;
return GRPC_SECURITY_OK;
return grpc_core::MakeRefCounted<grpc_alts_server_security_connector>(
std::move(server_creds));
}

@ -36,12 +36,13 @@
* - sc: address of ALTS channel security connector instance to be returned from
* the method.
*
* It returns GRPC_SECURITY_OK on success, and an error stauts code on failure.
* It returns nullptr on failure.
*/
grpc_security_status grpc_alts_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds, const char* target_name,
grpc_channel_security_connector** sc);
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_alts_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name);
/**
* This method creates an ALTS server security connector.
@ -50,17 +51,18 @@ grpc_security_status grpc_alts_channel_security_connector_create(
* - sc: address of ALTS server security connector instance to be returned from
* the method.
*
* It returns GRPC_SECURITY_OK on success, and an error status code on failure.
* It returns nullptr on failure.
*/
grpc_security_status grpc_alts_server_security_connector_create(
grpc_server_credentials* server_creds, grpc_server_security_connector** sc);
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds);
namespace grpc_core {
namespace internal {
/* Exposed only for testing. */
grpc_security_status grpc_alts_auth_context_from_tsi_peer(
const tsi_peer* peer, grpc_auth_context** ctx);
grpc_core::RefCountedPtr<grpc_auth_context>
grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer);
} // namespace internal
} // namespace grpc_core

@ -31,6 +31,7 @@
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
@ -38,91 +39,183 @@
#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/tsi/fake_transport_security.h"
typedef struct {
grpc_channel_security_connector base;
char* target;
char* expected_targets;
bool is_lb_channel;
char* target_name_override;
} grpc_fake_channel_security_connector;
namespace {
class grpc_fake_channel_security_connector final
: public grpc_channel_security_connector {
public:
grpc_fake_channel_security_connector(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target, const grpc_channel_args* args)
: grpc_channel_security_connector(GRPC_FAKE_SECURITY_URL_SCHEME,
std::move(channel_creds),
std::move(request_metadata_creds)),
target_(gpr_strdup(target)),
expected_targets_(
gpr_strdup(grpc_fake_transport_get_expected_targets(args))),
is_lb_channel_(grpc_core::FindTargetAuthorityTableInArgs(args) !=
nullptr) {
const grpc_arg* target_name_override_arg =
grpc_channel_args_find(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
if (target_name_override_arg != nullptr) {
target_name_override_ =
gpr_strdup(grpc_channel_arg_get_string(target_name_override_arg));
} else {
target_name_override_ = nullptr;
}
}
static void fake_channel_destroy(grpc_security_connector* sc) {
grpc_fake_channel_security_connector* c =
reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
grpc_call_credentials_unref(c->base.request_metadata_creds);
gpr_free(c->target);
gpr_free(c->expected_targets);
gpr_free(c->target_name_override);
gpr_free(c);
}
~grpc_fake_channel_security_connector() override {
gpr_free(target_);
gpr_free(expected_targets_);
if (target_name_override_ != nullptr) gpr_free(target_name_override_);
}
static void fake_server_destroy(grpc_security_connector* sc) { gpr_free(sc); }
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override;
static bool fake_check_target(const char* target_type, const char* target,
const char* set_str) {
GPR_ASSERT(target_type != nullptr);
GPR_ASSERT(target != nullptr);
char** set = nullptr;
size_t set_size = 0;
gpr_string_split(set_str, ",", &set, &set_size);
bool found = false;
for (size_t i = 0; i < set_size; ++i) {
if (set[i] != nullptr && strcmp(target, set[i]) == 0) found = true;
int cmp(const grpc_security_connector* other_sc) const override {
auto* other =
reinterpret_cast<const grpc_fake_channel_security_connector*>(other_sc);
int c = channel_security_connector_cmp(other);
if (c != 0) return c;
c = strcmp(target_, other->target_);
if (c != 0) return c;
if (expected_targets_ == nullptr || other->expected_targets_ == nullptr) {
c = GPR_ICMP(expected_targets_, other->expected_targets_);
} else {
c = strcmp(expected_targets_, other->expected_targets_);
}
if (c != 0) return c;
return GPR_ICMP(is_lb_channel_, other->is_lb_channel_);
}
for (size_t i = 0; i < set_size; ++i) {
gpr_free(set[i]);
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) override {
grpc_handshake_manager_add(
handshake_mgr,
grpc_security_handshaker_create(
tsi_create_fake_handshaker(/*is_client=*/true), this));
}
gpr_free(set);
return found;
}
static void fake_secure_name_check(const char* target,
const char* expected_targets,
bool is_lb_channel) {
if (expected_targets == nullptr) return;
char** lbs_and_backends = nullptr;
size_t lbs_and_backends_size = 0;
bool success = false;
gpr_string_split(expected_targets, ";", &lbs_and_backends,
&lbs_and_backends_size);
if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) {
gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'",
expected_targets);
goto done;
bool check_call_host(const char* host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) override {
char* authority_hostname = nullptr;
char* authority_ignored_port = nullptr;
char* target_hostname = nullptr;
char* target_ignored_port = nullptr;
gpr_split_host_port(host, &authority_hostname, &authority_ignored_port);
gpr_split_host_port(target_, &target_hostname, &target_ignored_port);
if (target_name_override_ != nullptr) {
char* fake_security_target_name_override_hostname = nullptr;
char* fake_security_target_name_override_ignored_port = nullptr;
gpr_split_host_port(target_name_override_,
&fake_security_target_name_override_hostname,
&fake_security_target_name_override_ignored_port);
if (strcmp(authority_hostname,
fake_security_target_name_override_hostname) != 0) {
gpr_log(GPR_ERROR,
"Authority (host) '%s' != Fake Security Target override '%s'",
host, fake_security_target_name_override_hostname);
abort();
}
gpr_free(fake_security_target_name_override_hostname);
gpr_free(fake_security_target_name_override_ignored_port);
} else if (strcmp(authority_hostname, target_hostname) != 0) {
gpr_log(GPR_ERROR, "Authority (host) '%s' != Target '%s'",
authority_hostname, target_hostname);
abort();
}
gpr_free(authority_hostname);
gpr_free(authority_ignored_port);
gpr_free(target_hostname);
gpr_free(target_ignored_port);
return true;
}
if (is_lb_channel) {
if (lbs_and_backends_size != 2) {
gpr_log(GPR_ERROR,
"Invalid expected targets arg value: '%s'. Expectations for LB "
"channels must be of the form 'be1,be2,be3,...;lb1,lb2,...",
expected_targets);
goto done;
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error* error) override {
GRPC_ERROR_UNREF(error);
}
char* target() const { return target_; }
char* expected_targets() const { return expected_targets_; }
bool is_lb_channel() const { return is_lb_channel_; }
char* target_name_override() const { return target_name_override_; }
private:
bool fake_check_target(const char* target_type, const char* target,
const char* set_str) const {
GPR_ASSERT(target_type != nullptr);
GPR_ASSERT(target != nullptr);
char** set = nullptr;
size_t set_size = 0;
gpr_string_split(set_str, ",", &set, &set_size);
bool found = false;
for (size_t i = 0; i < set_size; ++i) {
if (set[i] != nullptr && strcmp(target, set[i]) == 0) found = true;
}
if (!fake_check_target("LB", target, lbs_and_backends[1])) {
gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'",
target, lbs_and_backends[1]);
goto done;
for (size_t i = 0; i < set_size; ++i) {
gpr_free(set[i]);
}
success = true;
} else {
if (!fake_check_target("Backend", target, lbs_and_backends[0])) {
gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'",
target, lbs_and_backends[0]);
gpr_free(set);
return found;
}
void fake_secure_name_check() const {
if (expected_targets_ == nullptr) return;
char** lbs_and_backends = nullptr;
size_t lbs_and_backends_size = 0;
bool success = false;
gpr_string_split(expected_targets_, ";", &lbs_and_backends,
&lbs_and_backends_size);
if (lbs_and_backends_size > 2 || lbs_and_backends_size == 0) {
gpr_log(GPR_ERROR, "Invalid expected targets arg value: '%s'",
expected_targets_);
goto done;
}
success = true;
}
done:
for (size_t i = 0; i < lbs_and_backends_size; ++i) {
gpr_free(lbs_and_backends[i]);
if (is_lb_channel_) {
if (lbs_and_backends_size != 2) {
gpr_log(GPR_ERROR,
"Invalid expected targets arg value: '%s'. Expectations for LB "
"channels must be of the form 'be1,be2,be3,...;lb1,lb2,...",
expected_targets_);
goto done;
}
if (!fake_check_target("LB", target_, lbs_and_backends[1])) {
gpr_log(GPR_ERROR, "LB target '%s' not found in expected set '%s'",
target_, lbs_and_backends[1]);
goto done;
}
success = true;
} else {
if (!fake_check_target("Backend", target_, lbs_and_backends[0])) {
gpr_log(GPR_ERROR, "Backend target '%s' not found in expected set '%s'",
target_, lbs_and_backends[0]);
goto done;
}
success = true;
}
done:
for (size_t i = 0; i < lbs_and_backends_size; ++i) {
gpr_free(lbs_and_backends[i]);
}
gpr_free(lbs_and_backends);
if (!success) abort();
}
gpr_free(lbs_and_backends);
if (!success) abort();
}
static void fake_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
char* target_;
char* expected_targets_;
bool is_lb_channel_;
char* target_name_override_;
};
static void fake_check_peer(
grpc_security_connector* sc, tsi_peer peer,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) {
const char* prop_name;
grpc_error* error = GRPC_ERROR_NONE;
*auth_context = nullptr;
@ -147,164 +240,66 @@ static void fake_check_peer(grpc_security_connector* sc, tsi_peer peer,
"Invalid value for cert type property.");
goto end;
}
*auth_context = grpc_auth_context_create(nullptr);
*auth_context = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
grpc_auth_context_add_cstring_property(
*auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
auth_context->get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
end:
GRPC_CLOSURE_SCHED(on_peer_checked, error);
tsi_peer_destruct(&peer);
}
static void fake_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
fake_check_peer(sc, peer, auth_context, on_peer_checked);
grpc_fake_channel_security_connector* c =
reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
fake_secure_name_check(c->target, c->expected_targets, c->is_lb_channel);
void grpc_fake_channel_security_connector::check_peer(
tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) {
fake_check_peer(this, peer, auth_context, on_peer_checked);
fake_secure_name_check();
}
static void fake_server_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
fake_check_peer(sc, peer, auth_context, on_peer_checked);
}
class grpc_fake_server_security_connector
: public grpc_server_security_connector {
public:
grpc_fake_server_security_connector(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_server_security_connector(GRPC_FAKE_SECURITY_URL_SCHEME,
std::move(server_creds)) {}
~grpc_fake_server_security_connector() override = default;
static int fake_channel_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_fake_channel_security_connector* c1 =
reinterpret_cast<grpc_fake_channel_security_connector*>(sc1);
grpc_fake_channel_security_connector* c2 =
reinterpret_cast<grpc_fake_channel_security_connector*>(sc2);
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
if (c != 0) return c;
c = strcmp(c1->target, c2->target);
if (c != 0) return c;
if (c1->expected_targets == nullptr || c2->expected_targets == nullptr) {
c = GPR_ICMP(c1->expected_targets, c2->expected_targets);
} else {
c = strcmp(c1->expected_targets, c2->expected_targets);
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
fake_check_peer(this, peer, auth_context, on_peer_checked);
}
if (c != 0) return c;
return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel);
}
static int fake_server_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
return grpc_server_security_connector_cmp(
reinterpret_cast<grpc_server_security_connector*>(sc1),
reinterpret_cast<grpc_server_security_connector*>(sc2));
}
static bool fake_channel_check_call_host(grpc_channel_security_connector* sc,
const char* host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) {
grpc_fake_channel_security_connector* c =
reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
char* authority_hostname = nullptr;
char* authority_ignored_port = nullptr;
char* target_hostname = nullptr;
char* target_ignored_port = nullptr;
gpr_split_host_port(host, &authority_hostname, &authority_ignored_port);
gpr_split_host_port(c->target, &target_hostname, &target_ignored_port);
if (c->target_name_override != nullptr) {
char* fake_security_target_name_override_hostname = nullptr;
char* fake_security_target_name_override_ignored_port = nullptr;
gpr_split_host_port(c->target_name_override,
&fake_security_target_name_override_hostname,
&fake_security_target_name_override_ignored_port);
if (strcmp(authority_hostname,
fake_security_target_name_override_hostname) != 0) {
gpr_log(GPR_ERROR,
"Authority (host) '%s' != Fake Security Target override '%s'",
host, fake_security_target_name_override_hostname);
abort();
}
gpr_free(fake_security_target_name_override_hostname);
gpr_free(fake_security_target_name_override_ignored_port);
} else if (strcmp(authority_hostname, target_hostname) != 0) {
gpr_log(GPR_ERROR, "Authority (host) '%s' != Target '%s'",
authority_hostname, target_hostname);
abort();
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) override {
grpc_handshake_manager_add(
handshake_mgr,
grpc_security_handshaker_create(
tsi_create_fake_handshaker(/*=is_client*/ false), this));
}
gpr_free(authority_hostname);
gpr_free(authority_ignored_port);
gpr_free(target_hostname);
gpr_free(target_ignored_port);
return true;
}
static void fake_channel_cancel_check_call_host(
grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
static void fake_channel_add_handshakers(
grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_handshake_manager_add(
handshake_mgr,
grpc_security_handshaker_create(
tsi_create_fake_handshaker(true /* is_client */), &sc->base));
}
static void fake_server_add_handshakers(grpc_server_security_connector* sc,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_handshake_manager_add(
handshake_mgr,
grpc_security_handshaker_create(
tsi_create_fake_handshaker(false /* is_client */), &sc->base));
}
static grpc_security_connector_vtable fake_channel_vtable = {
fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp};
static grpc_security_connector_vtable fake_server_vtable = {
fake_server_destroy, fake_server_check_peer, fake_server_cmp};
grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds, const char* target,
const grpc_channel_args* args) {
grpc_fake_channel_security_connector* c =
static_cast<grpc_fake_channel_security_connector*>(
gpr_zalloc(sizeof(*c)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->base.base.vtable = &fake_channel_vtable;
c->base.channel_creds = channel_creds;
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = fake_channel_check_call_host;
c->base.cancel_check_call_host = fake_channel_cancel_check_call_host;
c->base.add_handshakers = fake_channel_add_handshakers;
c->target = gpr_strdup(target);
const char* expected_targets = grpc_fake_transport_get_expected_targets(args);
c->expected_targets = gpr_strdup(expected_targets);
c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr;
const grpc_arg* target_name_override_arg =
grpc_channel_args_find(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
if (target_name_override_arg != nullptr) {
c->target_name_override =
gpr_strdup(grpc_channel_arg_get_string(target_name_override_arg));
int cmp(const grpc_security_connector* other) const override {
return server_security_connector_cmp(
static_cast<const grpc_server_security_connector*>(other));
}
return &c->base;
};
} // namespace
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_fake_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target, const grpc_channel_args* args) {
return grpc_core::MakeRefCounted<grpc_fake_channel_security_connector>(
std::move(channel_creds), std::move(request_metadata_creds), target,
args);
}
grpc_server_security_connector* grpc_fake_server_security_connector_create(
grpc_server_credentials* server_creds) {
grpc_server_security_connector* c =
static_cast<grpc_server_security_connector*>(
gpr_zalloc(sizeof(grpc_server_security_connector)));
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->server_creds = server_creds;
c->add_handshakers = fake_server_add_handshakers;
return c;
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_fake_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
return grpc_core::MakeRefCounted<grpc_fake_server_security_connector>(
std::move(server_creds));
}

@ -24,19 +24,22 @@
#include <grpc/grpc_security.h>
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
/* Creates a fake connector that emulates real channel security. */
grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds, const char* target,
const grpc_channel_args* args);
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_fake_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target, const grpc_channel_args* args);
/* Creates a fake connector that emulates real server security. */
grpc_server_security_connector* grpc_fake_server_security_connector_create(
grpc_server_credentials* server_creds);
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_fake_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds);
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_FAKE_FAKE_SECURITY_CONNECTOR_H \
*/

@ -30,217 +30,224 @@
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/security/credentials/local/local_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/tsi/local_transport_security.h"
#define GRPC_UDS_URI_PATTERN "unix:"
#define GRPC_UDS_URL_SCHEME "unix"
#define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"
typedef struct {
grpc_channel_security_connector base;
char* target_name;
} grpc_local_channel_security_connector;
namespace {
typedef struct {
grpc_server_security_connector base;
} grpc_local_server_security_connector;
static void local_channel_destroy(grpc_security_connector* sc) {
if (sc == nullptr) {
return;
}
auto c = reinterpret_cast<grpc_local_channel_security_connector*>(sc);
grpc_call_credentials_unref(c->base.request_metadata_creds);
grpc_channel_credentials_unref(c->base.channel_creds);
gpr_free(c->target_name);
gpr_free(sc);
}
static void local_server_destroy(grpc_security_connector* sc) {
if (sc == nullptr) {
return;
}
auto c = reinterpret_cast<grpc_local_server_security_connector*>(sc);
grpc_server_credentials_unref(c->base.server_creds);
gpr_free(sc);
}
static void local_channel_add_handshakers(
grpc_channel_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
TSI_OK);
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
handshaker, &sc->base));
}
static void local_server_add_handshakers(
grpc_server_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) {
tsi_handshaker* handshaker = nullptr;
GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */, &handshaker) ==
TSI_OK);
grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
handshaker, &sc->base));
}
static int local_channel_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_local_channel_security_connector* c1 =
reinterpret_cast<grpc_local_channel_security_connector*>(sc1);
grpc_local_channel_security_connector* c2 =
reinterpret_cast<grpc_local_channel_security_connector*>(sc2);
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
if (c != 0) return c;
return strcmp(c1->target_name, c2->target_name);
}
static int local_server_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_local_server_security_connector* c1 =
reinterpret_cast<grpc_local_server_security_connector*>(sc1);
grpc_local_server_security_connector* c2 =
reinterpret_cast<grpc_local_server_security_connector*>(sc2);
return grpc_server_security_connector_cmp(&c1->base, &c2->base);
}
static grpc_security_status local_auth_context_create(grpc_auth_context** ctx) {
if (ctx == nullptr) {
gpr_log(GPR_ERROR, "Invalid arguments to local_auth_context_create()");
return GRPC_SECURITY_ERROR;
}
grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create() {
/* Create auth context. */
*ctx = grpc_auth_context_create(nullptr);
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
grpc_auth_context_add_cstring_property(
*ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
*ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
return GRPC_SECURITY_OK;
ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
return ctx;
}
static void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
grpc_security_status status;
void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked,
grpc_local_connect_type type) {
int fd = grpc_endpoint_get_fd(ep);
grpc_resolved_address resolved_addr;
memset(&resolved_addr, 0, sizeof(resolved_addr));
resolved_addr.len = GRPC_MAX_SOCKADDR_SIZE;
bool is_endpoint_local = false;
if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr),
&resolved_addr.len) == 0) {
grpc_resolved_address addr_normalized;
grpc_resolved_address* addr =
grpc_sockaddr_is_v4mapped(&resolved_addr, &addr_normalized)
? &addr_normalized
: &resolved_addr;
grpc_sockaddr* sock_addr = reinterpret_cast<grpc_sockaddr*>(&addr->addr);
// UDS
if (type == UDS && grpc_is_unix_socket(addr)) {
is_endpoint_local = true;
// IPV4
} else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET) {
const grpc_sockaddr_in* addr4 =
reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
if (grpc_htonl(addr4->sin_addr.s_addr) == INADDR_LOOPBACK) {
is_endpoint_local = true;
}
// IPv6
} else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET6) {
const grpc_sockaddr_in6* addr6 =
reinterpret_cast<const grpc_sockaddr_in6*>(addr);
if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
sizeof(in6addr_loopback)) == 0) {
is_endpoint_local = true;
}
}
}
grpc_error* error = GRPC_ERROR_NONE;
if (!is_endpoint_local) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Endpoint is neither UDS or TCP loopback address.");
GRPC_CLOSURE_SCHED(on_peer_checked, error);
return;
}
/* Create an auth context which is necessary to pass the santiy check in
* {client, server}_auth_filter that verifies if the peer's auth context is
* obtained during handshakes. The auth context is only checked for its
* existence and not actually used.
*/
status = local_auth_context_create(auth_context);
grpc_error* error = status == GRPC_SECURITY_OK
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Could not create local auth context");
*auth_context = local_auth_context_create();
error = *auth_context != nullptr ? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Could not create local auth context");
GRPC_CLOSURE_SCHED(on_peer_checked, error);
}
static grpc_security_connector_vtable local_channel_vtable = {
local_channel_destroy, local_check_peer, local_channel_cmp};
static grpc_security_connector_vtable local_server_vtable = {
local_server_destroy, local_check_peer, local_server_cmp};
static bool local_check_call_host(grpc_channel_security_connector* sc,
const char* host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) {
grpc_local_channel_security_connector* local_sc =
reinterpret_cast<grpc_local_channel_security_connector*>(sc);
if (host == nullptr || local_sc == nullptr ||
strcmp(host, local_sc->target_name) != 0) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"local call host does not match target name");
class grpc_local_channel_security_connector final
: public grpc_channel_security_connector {
public:
grpc_local_channel_security_connector(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const char* target_name)
: grpc_channel_security_connector(nullptr, std::move(channel_creds),
std::move(request_metadata_creds)),
target_name_(gpr_strdup(target_name)) {}
~grpc_local_channel_security_connector() override { gpr_free(target_name_); }
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) override {
tsi_handshaker* handshaker = nullptr;
GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
TSI_OK);
grpc_handshake_manager_add(
handshake_manager, grpc_security_handshaker_create(handshaker, this));
}
return true;
}
static void local_cancel_check_call_host(grpc_channel_security_connector* sc,
grpc_closure* on_call_host_checked,
grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
int cmp(const grpc_security_connector* other_sc) const override {
auto* other =
reinterpret_cast<const grpc_local_channel_security_connector*>(
other_sc);
int c = channel_security_connector_cmp(other);
if (c != 0) return c;
return strcmp(target_name_, other->target_name_);
}
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
grpc_local_credentials* creds =
reinterpret_cast<grpc_local_credentials*>(mutable_channel_creds());
local_check_peer(this, peer, ep, auth_context, on_peer_checked,
creds->connect_type());
}
bool check_call_host(const char* host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) override {
if (host == nullptr || strcmp(host, target_name_) != 0) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"local call host does not match target name");
}
return true;
}
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error* error) override {
GRPC_ERROR_UNREF(error);
}
grpc_security_status grpc_local_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds,
const grpc_channel_args* args, const char* target_name,
grpc_channel_security_connector** sc) {
if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) {
const char* target_name() const { return target_name_; }
private:
char* target_name_;
};
class grpc_local_server_security_connector final
: public grpc_server_security_connector {
public:
grpc_local_server_security_connector(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_server_security_connector(nullptr, std::move(server_creds)) {}
~grpc_local_server_security_connector() override = default;
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_manager) override {
tsi_handshaker* handshaker = nullptr;
GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */,
&handshaker) == TSI_OK);
grpc_handshake_manager_add(
handshake_manager, grpc_security_handshaker_create(handshaker, this));
}
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
grpc_local_server_credentials* creds =
static_cast<grpc_local_server_credentials*>(mutable_server_creds());
local_check_peer(this, peer, ep, auth_context, on_peer_checked,
creds->connect_type());
}
int cmp(const grpc_security_connector* other) const override {
return server_security_connector_cmp(
static_cast<const grpc_server_security_connector*>(other));
}
};
} // namespace
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const grpc_channel_args* args, const char* target_name) {
if (channel_creds == nullptr || target_name == nullptr) {
gpr_log(
GPR_ERROR,
"Invalid arguments to grpc_local_channel_security_connector_create()");
return GRPC_SECURITY_ERROR;
return nullptr;
}
// Check if local_connect_type is UDS. Only UDS is supported for now.
// Perform sanity check on UDS address. For TCP local connection, the check
// will be done during check_peer procedure.
grpc_local_credentials* creds =
reinterpret_cast<grpc_local_credentials*>(channel_creds);
if (creds->connect_type != UDS) {
gpr_log(GPR_ERROR,
"Invalid local channel type to "
"grpc_local_channel_security_connector_create()");
return GRPC_SECURITY_ERROR;
}
// Check if target_name is a valid UDS address.
static_cast<grpc_local_credentials*>(channel_creds.get());
const grpc_arg* server_uri_arg =
grpc_channel_args_find(args, GRPC_ARG_SERVER_URI);
const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
if (strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
if (creds->connect_type() == UDS &&
strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
strlen(GRPC_UDS_URI_PATTERN)) != 0) {
gpr_log(GPR_ERROR,
"Invalid target_name to "
"Invalid UDS target name to "
"grpc_local_channel_security_connector_create()");
return GRPC_SECURITY_ERROR;
return nullptr;
}
auto c = static_cast<grpc_local_channel_security_connector*>(
gpr_zalloc(sizeof(grpc_local_channel_security_connector)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &local_channel_vtable;
c->base.add_handshakers = local_channel_add_handshakers;
c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = local_check_call_host;
c->base.cancel_check_call_host = local_cancel_check_call_host;
c->base.base.url_scheme =
creds->connect_type == UDS ? GRPC_UDS_URL_SCHEME : nullptr;
c->target_name = gpr_strdup(target_name);
*sc = &c->base;
return GRPC_SECURITY_OK;
return grpc_core::MakeRefCounted<grpc_local_channel_security_connector>(
channel_creds, request_metadata_creds, target_name);
}
grpc_security_status grpc_local_server_security_connector_create(
grpc_server_credentials* server_creds,
grpc_server_security_connector** sc) {
if (server_creds == nullptr || sc == nullptr) {
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
if (server_creds == nullptr) {
gpr_log(
GPR_ERROR,
"Invalid arguments to grpc_local_server_security_connector_create()");
return GRPC_SECURITY_ERROR;
}
// Check if local_connect_type is UDS. Only UDS is supported for now.
grpc_local_server_credentials* creds =
reinterpret_cast<grpc_local_server_credentials*>(server_creds);
if (creds->connect_type != UDS) {
gpr_log(GPR_ERROR,
"Invalid local server type to "
"grpc_local_server_security_connector_create()");
return GRPC_SECURITY_ERROR;
return nullptr;
}
auto c = static_cast<grpc_local_server_security_connector*>(
gpr_zalloc(sizeof(grpc_local_server_security_connector)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &local_server_vtable;
c->base.server_creds = grpc_server_credentials_ref(server_creds);
c->base.base.url_scheme =
creds->connect_type == UDS ? GRPC_UDS_URL_SCHEME : nullptr;
c->base.add_handshakers = local_server_add_handshakers;
*sc = &c->base;
return GRPC_SECURITY_OK;
return grpc_core::MakeRefCounted<grpc_local_server_security_connector>(
std::move(server_creds));
}

@ -34,13 +34,13 @@
* - sc: address of local channel security connector instance to be returned
* from the method.
*
* It returns GRPC_SECURITY_OK on success, and an error stauts code on failure.
* It returns nullptr on failure.
*/
grpc_security_status grpc_local_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds,
const grpc_channel_args* args, const char* target_name,
grpc_channel_security_connector** sc);
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const grpc_channel_args* args, const char* target_name);
/**
* This method creates a local server security connector.
@ -49,10 +49,11 @@ grpc_security_status grpc_local_channel_security_connector_create(
* - sc: address of local server security connector instance to be returned from
* the method.
*
* It returns GRPC_SECURITY_OK on success, and an error status code on failure.
* It returns nullptr on failure.
*/
grpc_security_status grpc_local_server_security_connector_create(
grpc_server_credentials* server_creds, grpc_server_security_connector** sc);
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds);
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_LOCAL_LOCAL_SECURITY_CONNECTOR_H \
*/

@ -35,150 +35,67 @@
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/load_system_roots.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/lib/security/transport/security_handshaker.h"
grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount(
false, "security_connector_refcount");
void grpc_channel_security_connector_add_handshakers(
grpc_channel_security_connector* connector,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
if (connector != nullptr) {
connector->add_handshakers(connector, interested_parties, handshake_mgr);
}
}
void grpc_server_security_connector_add_handshakers(
grpc_server_security_connector* connector,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
if (connector != nullptr) {
connector->add_handshakers(connector, interested_parties, handshake_mgr);
}
}
void grpc_security_connector_check_peer(grpc_security_connector* sc,
tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
if (sc == nullptr) {
GRPC_CLOSURE_SCHED(on_peer_checked,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"cannot check peer -- no security connector"));
tsi_peer_destruct(&peer);
} else {
sc->vtable->check_peer(sc, peer, auth_context, on_peer_checked);
}
}
int grpc_security_connector_cmp(grpc_security_connector* sc,
grpc_security_connector* other) {
grpc_server_security_connector::grpc_server_security_connector(
const char* url_scheme,
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_security_connector(url_scheme),
server_creds_(std::move(server_creds)) {}
grpc_channel_security_connector::grpc_channel_security_connector(
const char* url_scheme,
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds)
: grpc_security_connector(url_scheme),
channel_creds_(std::move(channel_creds)),
request_metadata_creds_(std::move(request_metadata_creds)) {}
grpc_channel_security_connector::~grpc_channel_security_connector() {}
int grpc_security_connector_cmp(const grpc_security_connector* sc,
const grpc_security_connector* other) {
if (sc == nullptr || other == nullptr) return GPR_ICMP(sc, other);
int c = GPR_ICMP(sc->vtable, other->vtable);
if (c != 0) return c;
return sc->vtable->cmp(sc, other);
return sc->cmp(other);
}
int grpc_channel_security_connector_cmp(grpc_channel_security_connector* sc1,
grpc_channel_security_connector* sc2) {
GPR_ASSERT(sc1->channel_creds != nullptr);
GPR_ASSERT(sc2->channel_creds != nullptr);
int c = GPR_ICMP(sc1->channel_creds, sc2->channel_creds);
if (c != 0) return c;
c = GPR_ICMP(sc1->request_metadata_creds, sc2->request_metadata_creds);
if (c != 0) return c;
c = GPR_ICMP((void*)sc1->check_call_host, (void*)sc2->check_call_host);
if (c != 0) return c;
c = GPR_ICMP((void*)sc1->cancel_check_call_host,
(void*)sc2->cancel_check_call_host);
int grpc_channel_security_connector::channel_security_connector_cmp(
const grpc_channel_security_connector* other) const {
const grpc_channel_security_connector* other_sc =
static_cast<const grpc_channel_security_connector*>(other);
GPR_ASSERT(channel_creds() != nullptr);
GPR_ASSERT(other_sc->channel_creds() != nullptr);
int c = GPR_ICMP(channel_creds(), other_sc->channel_creds());
if (c != 0) return c;
return GPR_ICMP((void*)sc1->add_handshakers, (void*)sc2->add_handshakers);
return GPR_ICMP(request_metadata_creds(), other_sc->request_metadata_creds());
}
int grpc_server_security_connector_cmp(grpc_server_security_connector* sc1,
grpc_server_security_connector* sc2) {
GPR_ASSERT(sc1->server_creds != nullptr);
GPR_ASSERT(sc2->server_creds != nullptr);
int c = GPR_ICMP(sc1->server_creds, sc2->server_creds);
if (c != 0) return c;
return GPR_ICMP((void*)sc1->add_handshakers, (void*)sc2->add_handshakers);
}
bool grpc_channel_security_connector_check_call_host(
grpc_channel_security_connector* sc, const char* host,
grpc_auth_context* auth_context, grpc_closure* on_call_host_checked,
grpc_error** error) {
if (sc == nullptr || sc->check_call_host == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"cannot check call host -- no security connector");
return true;
}
return sc->check_call_host(sc, host, auth_context, on_call_host_checked,
error);
}
void grpc_channel_security_connector_cancel_check_call_host(
grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
grpc_error* error) {
if (sc == nullptr || sc->cancel_check_call_host == nullptr) {
GRPC_ERROR_UNREF(error);
return;
}
sc->cancel_check_call_host(sc, on_call_host_checked, error);
}
#ifndef NDEBUG
grpc_security_connector* grpc_security_connector_ref(
grpc_security_connector* sc, const char* file, int line,
const char* reason) {
if (sc == nullptr) return nullptr;
if (grpc_trace_security_connector_refcount.enabled()) {
gpr_atm val = gpr_atm_no_barrier_load(&sc->refcount.count);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"SECURITY_CONNECTOR:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", sc,
val, val + 1, reason);
}
#else
grpc_security_connector* grpc_security_connector_ref(
grpc_security_connector* sc) {
if (sc == nullptr) return nullptr;
#endif
gpr_ref(&sc->refcount);
return sc;
}
#ifndef NDEBUG
void grpc_security_connector_unref(grpc_security_connector* sc,
const char* file, int line,
const char* reason) {
if (sc == nullptr) return;
if (grpc_trace_security_connector_refcount.enabled()) {
gpr_atm val = gpr_atm_no_barrier_load(&sc->refcount.count);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"SECURITY_CONNECTOR:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", sc,
val, val - 1, reason);
}
#else
void grpc_security_connector_unref(grpc_security_connector* sc) {
if (sc == nullptr) return;
#endif
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
int grpc_server_security_connector::server_security_connector_cmp(
const grpc_server_security_connector* other) const {
const grpc_server_security_connector* other_sc =
static_cast<const grpc_server_security_connector*>(other);
GPR_ASSERT(server_creds() != nullptr);
GPR_ASSERT(other_sc->server_creds() != nullptr);
return GPR_ICMP(server_creds(), other_sc->server_creds());
}
static void connector_arg_destroy(void* p) {
GRPC_SECURITY_CONNECTOR_UNREF((grpc_security_connector*)p,
"connector_arg_destroy");
static_cast<grpc_security_connector*>(p)->Unref(DEBUG_LOCATION,
"connector_arg_destroy");
}
static void* connector_arg_copy(void* p) {
return GRPC_SECURITY_CONNECTOR_REF((grpc_security_connector*)p,
"connector_arg_copy");
return static_cast<grpc_security_connector*>(p)
->Ref(DEBUG_LOCATION, "connector_arg_copy")
.release();
}
static int connector_cmp(void* a, void* b) {
return grpc_security_connector_cmp(static_cast<grpc_security_connector*>(a),
static_cast<grpc_security_connector*>(b));
return static_cast<grpc_security_connector*>(a)->cmp(
static_cast<grpc_security_connector*>(b));
}
static const grpc_arg_pointer_vtable connector_arg_vtable = {

@ -26,6 +26,7 @@
#include <grpc/grpc_security.h>
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/tcp_server.h"
@ -34,8 +35,6 @@
extern grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount;
/* --- status enum. --- */
typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
/* --- security_connector object. ---
@ -43,54 +42,34 @@ typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
A security connector object represents away to configure the underlying
transport security mechanism and check the resulting trusted peer. */
typedef struct grpc_security_connector grpc_security_connector;
#define GRPC_ARG_SECURITY_CONNECTOR "grpc.security_connector"
typedef struct {
void (*destroy)(grpc_security_connector* sc);
void (*check_peer)(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked);
int (*cmp)(grpc_security_connector* sc, grpc_security_connector* other);
} grpc_security_connector_vtable;
struct grpc_security_connector {
const grpc_security_connector_vtable* vtable;
gpr_refcount refcount;
const char* url_scheme;
};
class grpc_security_connector
: public grpc_core::RefCounted<grpc_security_connector> {
public:
explicit grpc_security_connector(const char* url_scheme)
: grpc_core::RefCounted<grpc_security_connector>(
&grpc_trace_security_connector_refcount),
url_scheme_(url_scheme) {}
virtual ~grpc_security_connector() = default;
/* Check the peer. Callee takes ownership of the peer object.
When done, sets *auth_context and invokes on_peer_checked. */
virtual void check_peer(
tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) GRPC_ABSTRACT;
/* Compares two security connectors. */
virtual int cmp(const grpc_security_connector* other) const GRPC_ABSTRACT;
const char* url_scheme() const { return url_scheme_; }
/* Refcounting. */
#ifndef NDEBUG
#define GRPC_SECURITY_CONNECTOR_REF(p, r) \
grpc_security_connector_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \
grpc_security_connector_unref((p), __FILE__, __LINE__, (r))
grpc_security_connector* grpc_security_connector_ref(
grpc_security_connector* policy, const char* file, int line,
const char* reason);
void grpc_security_connector_unref(grpc_security_connector* policy,
const char* file, int line,
const char* reason);
#else
#define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p))
#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p))
grpc_security_connector* grpc_security_connector_ref(
grpc_security_connector* policy);
void grpc_security_connector_unref(grpc_security_connector* policy);
#endif
/* Check the peer. Callee takes ownership of the peer object.
When done, sets *auth_context and invokes on_peer_checked. */
void grpc_security_connector_check_peer(grpc_security_connector* sc,
tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked);
/* Compares two security connectors. */
int grpc_security_connector_cmp(grpc_security_connector* sc,
grpc_security_connector* other);
GRPC_ABSTRACT_BASE_CLASS
private:
const char* url_scheme_;
};
/* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector* sc);
@ -107,71 +86,89 @@ grpc_security_connector* grpc_security_connector_find_in_args(
A channel security connector object represents a way to configure the
underlying transport security mechanism on the client side. */
typedef struct grpc_channel_security_connector grpc_channel_security_connector;
struct grpc_channel_security_connector {
grpc_security_connector base;
grpc_channel_credentials* channel_creds;
grpc_call_credentials* request_metadata_creds;
bool (*check_call_host)(grpc_channel_security_connector* sc, const char* host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error);
void (*cancel_check_call_host)(grpc_channel_security_connector* sc,
grpc_closure* on_call_host_checked,
grpc_error* error);
void (*add_handshakers)(grpc_channel_security_connector* sc,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
class grpc_channel_security_connector : public grpc_security_connector {
public:
grpc_channel_security_connector(
const char* url_scheme,
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds);
~grpc_channel_security_connector() override;
/// Checks that the host that will be set for a call is acceptable.
/// Returns true if completed synchronously, in which case \a error will
/// be set to indicate the result. Otherwise, \a on_call_host_checked
/// will be invoked when complete.
virtual bool check_call_host(const char* host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) GRPC_ABSTRACT;
/// Cancels a pending asychronous call to
/// grpc_channel_security_connector_check_call_host() with
/// \a on_call_host_checked as its callback.
virtual void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error* error) GRPC_ABSTRACT;
/// Registers handshakers with \a handshake_mgr.
virtual void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr)
GRPC_ABSTRACT;
const grpc_channel_credentials* channel_creds() const {
return channel_creds_.get();
}
grpc_channel_credentials* mutable_channel_creds() {
return channel_creds_.get();
}
const grpc_call_credentials* request_metadata_creds() const {
return request_metadata_creds_.get();
}
grpc_call_credentials* mutable_request_metadata_creds() {
return request_metadata_creds_.get();
}
GRPC_ABSTRACT_BASE_CLASS
protected:
// Helper methods to be used in subclasses.
int channel_security_connector_cmp(
const grpc_channel_security_connector* other) const;
private:
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds_;
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds_;
};
/// A helper function for use in grpc_security_connector_cmp() implementations.
int grpc_channel_security_connector_cmp(grpc_channel_security_connector* sc1,
grpc_channel_security_connector* sc2);
/// Checks that the host that will be set for a call is acceptable.
/// Returns true if completed synchronously, in which case \a error will
/// be set to indicate the result. Otherwise, \a on_call_host_checked
/// will be invoked when complete.
bool grpc_channel_security_connector_check_call_host(
grpc_channel_security_connector* sc, const char* host,
grpc_auth_context* auth_context, grpc_closure* on_call_host_checked,
grpc_error** error);
/// Cancels a pending asychronous call to
/// grpc_channel_security_connector_check_call_host() with
/// \a on_call_host_checked as its callback.
void grpc_channel_security_connector_cancel_check_call_host(
grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
grpc_error* error);
/* Registers handshakers with \a handshake_mgr. */
void grpc_channel_security_connector_add_handshakers(
grpc_channel_security_connector* connector,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
/* --- server_security_connector object. ---
A server security connector object represents a way to configure the
underlying transport security mechanism on the server side. */
typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector {
grpc_security_connector base;
grpc_server_credentials* server_creds;
void (*add_handshakers)(grpc_server_security_connector* sc,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
class grpc_server_security_connector : public grpc_security_connector {
public:
grpc_server_security_connector(
const char* url_scheme,
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds);
~grpc_server_security_connector() override = default;
virtual void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr)
GRPC_ABSTRACT;
const grpc_server_credentials* server_creds() const {
return server_creds_.get();
}
grpc_server_credentials* mutable_server_creds() {
return server_creds_.get();
}
GRPC_ABSTRACT_BASE_CLASS
protected:
// Helper methods to be used in subclasses.
int server_security_connector_cmp(
const grpc_server_security_connector* other) const;
private:
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds_;
};
/// A helper function for use in grpc_security_connector_cmp() implementations.
int grpc_server_security_connector_cmp(grpc_server_security_connector* sc1,
grpc_server_security_connector* sc2);
void grpc_server_security_connector_add_handshakers(
grpc_server_security_connector* sc, grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr);
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SECURITY_CONNECTOR_H */

@ -30,6 +30,7 @@
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
@ -39,172 +40,10 @@
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security.h"
typedef struct {
grpc_channel_security_connector base;
tsi_ssl_client_handshaker_factory* client_handshaker_factory;
char* target_name;
char* overridden_target_name;
const verify_peer_options* verify_options;
} grpc_ssl_channel_security_connector;
typedef struct {
grpc_server_security_connector base;
tsi_ssl_server_handshaker_factory* server_handshaker_factory;
} grpc_ssl_server_security_connector;
static bool server_connector_has_cert_config_fetcher(
grpc_ssl_server_security_connector* c) {
GPR_ASSERT(c != nullptr);
grpc_ssl_server_credentials* server_creds =
reinterpret_cast<grpc_ssl_server_credentials*>(c->base.server_creds);
GPR_ASSERT(server_creds != nullptr);
return server_creds->certificate_config_fetcher.cb != nullptr;
}
static void ssl_channel_destroy(grpc_security_connector* sc) {
grpc_ssl_channel_security_connector* c =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
grpc_channel_credentials_unref(c->base.channel_creds);
grpc_call_credentials_unref(c->base.request_metadata_creds);
tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory);
c->client_handshaker_factory = nullptr;
if (c->target_name != nullptr) gpr_free(c->target_name);
if (c->overridden_target_name != nullptr) gpr_free(c->overridden_target_name);
gpr_free(sc);
}
static void ssl_server_destroy(grpc_security_connector* sc) {
grpc_ssl_server_security_connector* c =
reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
grpc_server_credentials_unref(c->base.server_creds);
tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory);
c->server_handshaker_factory = nullptr;
gpr_free(sc);
}
static void ssl_channel_add_handshakers(grpc_channel_security_connector* sc,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_ssl_channel_security_connector* c =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
// Instantiate TSI handshaker.
tsi_handshaker* tsi_hs = nullptr;
tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
c->client_handshaker_factory,
c->overridden_target_name != nullptr ? c->overridden_target_name
: c->target_name,
&tsi_hs);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return;
}
// Create handshakers.
grpc_handshake_manager_add(
handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base));
}
/* Attempts to replace the server_handshaker_factory with a new factory using
* the provided grpc_ssl_server_certificate_config. Should new factory creation
* fail, the existing factory will not be replaced. Returns true on success (new
* factory created). */
static bool try_replace_server_handshaker_factory(
grpc_ssl_server_security_connector* sc,
const grpc_ssl_server_certificate_config* config) {
if (config == nullptr) {
gpr_log(GPR_ERROR,
"Server certificate config callback returned invalid (NULL) "
"config.");
return false;
}
gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config);
size_t num_alpn_protocols = 0;
const char** alpn_protocol_strings =
grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
tsi_ssl_pem_key_cert_pair* cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
config->pem_key_cert_pairs, config->num_key_cert_pairs);
tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr;
grpc_ssl_server_credentials* server_creds =
reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
tsi_result result = tsi_create_ssl_server_handshaker_factory_ex(
cert_pairs, config->num_key_cert_pairs, config->pem_root_certs,
grpc_get_tsi_client_certificate_request_type(
server_creds->config.client_certificate_request),
grpc_get_ssl_cipher_suites(), alpn_protocol_strings,
static_cast<uint16_t>(num_alpn_protocols), &new_handshaker_factory);
gpr_free(cert_pairs);
gpr_free((void*)alpn_protocol_strings);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
return false;
}
tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory);
sc->server_handshaker_factory = new_handshaker_factory;
return true;
}
/* Attempts to fetch the server certificate config if a callback is available.
* Current certificate config will continue to be used if the callback returns
* an error. Returns true if new credentials were sucessfully loaded. */
static bool try_fetch_ssl_server_credentials(
grpc_ssl_server_security_connector* sc) {
grpc_ssl_server_certificate_config* certificate_config = nullptr;
bool status;
GPR_ASSERT(sc != nullptr);
if (!server_connector_has_cert_config_fetcher(sc)) return false;
grpc_ssl_server_credentials* server_creds =
reinterpret_cast<grpc_ssl_server_credentials*>(sc->base.server_creds);
grpc_ssl_certificate_config_reload_status cb_result =
server_creds->certificate_config_fetcher.cb(
server_creds->certificate_config_fetcher.user_data,
&certificate_config);
if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) {
gpr_log(GPR_DEBUG, "No change in SSL server credentials.");
status = false;
} else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) {
status = try_replace_server_handshaker_factory(sc, certificate_config);
} else {
// Log error, continue using previously-loaded credentials.
gpr_log(GPR_ERROR,
"Failed fetching new server credentials, continuing to "
"use previously-loaded credentials.");
status = false;
}
if (certificate_config != nullptr) {
grpc_ssl_server_certificate_config_destroy(certificate_config);
}
return status;
}
static void ssl_server_add_handshakers(grpc_server_security_connector* sc,
grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) {
grpc_ssl_server_security_connector* c =
reinterpret_cast<grpc_ssl_server_security_connector*>(sc);
// Instantiate TSI handshaker.
try_fetch_ssl_server_credentials(c);
tsi_handshaker* tsi_hs = nullptr;
tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
c->server_handshaker_factory, &tsi_hs);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return;
}
// Create handshakers.
grpc_handshake_manager_add(
handshake_mgr, grpc_security_handshaker_create(tsi_hs, &sc->base));
}
static grpc_error* ssl_check_peer(grpc_security_connector* sc,
const char* peer_name, const tsi_peer* peer,
grpc_auth_context** auth_context) {
namespace {
grpc_error* ssl_check_peer(
const char* peer_name, const tsi_peer* peer,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context) {
#if TSI_OPENSSL_ALPN_SUPPORT
/* Check the ALPN if ALPN is supported. */
const tsi_peer_property* p =
@ -230,245 +69,384 @@ static grpc_error* ssl_check_peer(grpc_security_connector* sc,
return GRPC_ERROR_NONE;
}
static void ssl_channel_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
grpc_ssl_channel_security_connector* c =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
const char* target_name = c->overridden_target_name != nullptr
? c->overridden_target_name
: c->target_name;
grpc_error* error = ssl_check_peer(sc, target_name, &peer, auth_context);
if (error == GRPC_ERROR_NONE &&
c->verify_options->verify_peer_callback != nullptr) {
const tsi_peer_property* p =
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
if (p == nullptr) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: missing pem cert property.");
} else {
char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
memcpy(peer_pem, p->value.data, p->value.length);
peer_pem[p->value.length] = '\0';
int callback_status = c->verify_options->verify_peer_callback(
target_name, peer_pem,
c->verify_options->verify_peer_callback_userdata);
gpr_free(peer_pem);
if (callback_status) {
char* msg;
gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)",
callback_status);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
}
}
class grpc_ssl_channel_security_connector final
: public grpc_channel_security_connector {
public:
grpc_ssl_channel_security_connector(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const grpc_ssl_config* config, const char* target_name,
const char* overridden_target_name)
: grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
std::move(channel_creds),
std::move(request_metadata_creds)),
overridden_target_name_(overridden_target_name == nullptr
? nullptr
: gpr_strdup(overridden_target_name)),
verify_options_(&config->verify_options) {
char* port;
gpr_split_host_port(target_name, &target_name_, &port);
gpr_free(port);
}
GRPC_CLOSURE_SCHED(on_peer_checked, error);
tsi_peer_destruct(&peer);
}
static void ssl_server_check_peer(grpc_security_connector* sc, tsi_peer peer,
grpc_auth_context** auth_context,
grpc_closure* on_peer_checked) {
grpc_error* error = ssl_check_peer(sc, nullptr, &peer, auth_context);
tsi_peer_destruct(&peer);
GRPC_CLOSURE_SCHED(on_peer_checked, error);
}
~grpc_ssl_channel_security_connector() override {
tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_);
if (target_name_ != nullptr) gpr_free(target_name_);
if (overridden_target_name_ != nullptr) gpr_free(overridden_target_name_);
}
static int ssl_channel_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
grpc_ssl_channel_security_connector* c1 =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc1);
grpc_ssl_channel_security_connector* c2 =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc2);
int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
if (c != 0) return c;
c = strcmp(c1->target_name, c2->target_name);
if (c != 0) return c;
return (c1->overridden_target_name == nullptr ||
c2->overridden_target_name == nullptr)
? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name)
: strcmp(c1->overridden_target_name, c2->overridden_target_name);
}
grpc_security_status InitializeHandshakerFactory(
const grpc_ssl_config* config, const char* pem_root_certs,
const tsi_ssl_root_certs_store* root_store,
tsi_ssl_session_cache* ssl_session_cache) {
bool has_key_cert_pair =
config->pem_key_cert_pair != nullptr &&
config->pem_key_cert_pair->private_key != nullptr &&
config->pem_key_cert_pair->cert_chain != nullptr;
tsi_ssl_client_handshaker_options options;
memset(&options, 0, sizeof(options));
GPR_DEBUG_ASSERT(pem_root_certs != nullptr);
options.pem_root_certs = pem_root_certs;
options.root_store = root_store;
options.alpn_protocols =
grpc_fill_alpn_protocol_strings(&options.num_alpn_protocols);
if (has_key_cert_pair) {
options.pem_key_cert_pair = config->pem_key_cert_pair;
}
options.cipher_suites = grpc_get_ssl_cipher_suites();
options.session_cache = ssl_session_cache;
const tsi_result result =
tsi_create_ssl_client_handshaker_factory_with_options(
&options, &client_handshaker_factory_);
gpr_free((void*)options.alpn_protocols);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
return GRPC_SECURITY_ERROR;
}
return GRPC_SECURITY_OK;
}
static int ssl_server_cmp(grpc_security_connector* sc1,
grpc_security_connector* sc2) {
return grpc_server_security_connector_cmp(
reinterpret_cast<grpc_server_security_connector*>(sc1),
reinterpret_cast<grpc_server_security_connector*>(sc2));
}
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) override {
// Instantiate TSI handshaker.
tsi_handshaker* tsi_hs = nullptr;
tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
client_handshaker_factory_,
overridden_target_name_ != nullptr ? overridden_target_name_
: target_name_,
&tsi_hs);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return;
}
// Create handshakers.
grpc_handshake_manager_add(handshake_mgr,
grpc_security_handshaker_create(tsi_hs, this));
}
static bool ssl_channel_check_call_host(grpc_channel_security_connector* sc,
const char* host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) {
grpc_ssl_channel_security_connector* c =
reinterpret_cast<grpc_ssl_channel_security_connector*>(sc);
grpc_security_status status = GRPC_SECURITY_ERROR;
tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
/* If the target name was overridden, then the original target_name was
'checked' transitively during the previous peer check at the end of the
handshake. */
if (c->overridden_target_name != nullptr &&
strcmp(host, c->target_name) == 0) {
status = GRPC_SECURITY_OK;
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
const char* target_name = overridden_target_name_ != nullptr
? overridden_target_name_
: target_name_;
grpc_error* error = ssl_check_peer(target_name, &peer, auth_context);
if (error == GRPC_ERROR_NONE &&
verify_options_->verify_peer_callback != nullptr) {
const tsi_peer_property* p =
tsi_peer_get_property_by_name(&peer, TSI_X509_PEM_CERT_PROPERTY);
if (p == nullptr) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: missing pem cert property.");
} else {
char* peer_pem = static_cast<char*>(gpr_malloc(p->value.length + 1));
memcpy(peer_pem, p->value.data, p->value.length);
peer_pem[p->value.length] = '\0';
int callback_status = verify_options_->verify_peer_callback(
target_name, peer_pem,
verify_options_->verify_peer_callback_userdata);
gpr_free(peer_pem);
if (callback_status) {
char* msg;
gpr_asprintf(&msg, "Verify peer callback returned a failure (%d)",
callback_status);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
}
}
}
GRPC_CLOSURE_SCHED(on_peer_checked, error);
tsi_peer_destruct(&peer);
}
if (status != GRPC_SECURITY_OK) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"call host does not match SSL server name");
int cmp(const grpc_security_connector* other_sc) const override {
auto* other =
reinterpret_cast<const grpc_ssl_channel_security_connector*>(other_sc);
int c = channel_security_connector_cmp(other);
if (c != 0) return c;
c = strcmp(target_name_, other->target_name_);
if (c != 0) return c;
return (overridden_target_name_ == nullptr ||
other->overridden_target_name_ == nullptr)
? GPR_ICMP(overridden_target_name_,
other->overridden_target_name_)
: strcmp(overridden_target_name_,
other->overridden_target_name_);
}
grpc_shallow_peer_destruct(&peer);
return true;
}
static void ssl_channel_cancel_check_call_host(
grpc_channel_security_connector* sc, grpc_closure* on_call_host_checked,
grpc_error* error) {
GRPC_ERROR_UNREF(error);
}
bool check_call_host(const char* host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) override {
grpc_security_status status = GRPC_SECURITY_ERROR;
tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
/* If the target name was overridden, then the original target_name was
'checked' transitively during the previous peer check at the end of the
handshake. */
if (overridden_target_name_ != nullptr && strcmp(host, target_name_) == 0) {
status = GRPC_SECURITY_OK;
}
if (status != GRPC_SECURITY_OK) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"call host does not match SSL server name");
}
grpc_shallow_peer_destruct(&peer);
return true;
}
static grpc_security_connector_vtable ssl_channel_vtable = {
ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp};
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error* error) override {
GRPC_ERROR_UNREF(error);
}
static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp};
private:
tsi_ssl_client_handshaker_factory* client_handshaker_factory_;
char* target_name_;
char* overridden_target_name_;
const verify_peer_options* verify_options_;
};
class grpc_ssl_server_security_connector
: public grpc_server_security_connector {
public:
grpc_ssl_server_security_connector(
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
std::move(server_creds)) {}
~grpc_ssl_server_security_connector() override {
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
}
grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds,
const grpc_ssl_config* config, const char* target_name,
const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache,
grpc_channel_security_connector** sc) {
tsi_result result = TSI_OK;
grpc_ssl_channel_security_connector* c;
char* port;
bool has_key_cert_pair;
tsi_ssl_client_handshaker_options options;
memset(&options, 0, sizeof(options));
options.alpn_protocols =
grpc_fill_alpn_protocol_strings(&options.num_alpn_protocols);
bool has_cert_config_fetcher() const {
return static_cast<const grpc_ssl_server_credentials*>(server_creds())
->has_cert_config_fetcher();
}
if (config == nullptr || target_name == nullptr) {
gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
goto error;
const tsi_ssl_server_handshaker_factory* server_handshaker_factory() const {
return server_handshaker_factory_;
}
if (config->pem_root_certs == nullptr) {
// Use default root certificates.
options.pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
options.root_store = grpc_core::DefaultSslRootStore::GetRootStore();
if (options.pem_root_certs == nullptr) {
gpr_log(GPR_ERROR, "Could not get default pem root certs.");
goto error;
grpc_security_status InitializeHandshakerFactory() {
if (has_cert_config_fetcher()) {
// Load initial credentials from certificate_config_fetcher:
if (!try_fetch_ssl_server_credentials()) {
gpr_log(GPR_ERROR,
"Failed loading SSL server credentials from fetcher.");
return GRPC_SECURITY_ERROR;
}
} else {
auto* server_credentials =
static_cast<const grpc_ssl_server_credentials*>(server_creds());
size_t num_alpn_protocols = 0;
const char** alpn_protocol_strings =
grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
const tsi_result result = tsi_create_ssl_server_handshaker_factory_ex(
server_credentials->config().pem_key_cert_pairs,
server_credentials->config().num_key_cert_pairs,
server_credentials->config().pem_root_certs,
grpc_get_tsi_client_certificate_request_type(
server_credentials->config().client_certificate_request),
grpc_get_ssl_cipher_suites(), alpn_protocol_strings,
static_cast<uint16_t>(num_alpn_protocols),
&server_handshaker_factory_);
gpr_free((void*)alpn_protocol_strings);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
return GRPC_SECURITY_ERROR;
}
}
} else {
options.pem_root_certs = config->pem_root_certs;
}
c = static_cast<grpc_ssl_channel_security_connector*>(
gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &ssl_channel_vtable;
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host;
c->base.cancel_check_call_host = ssl_channel_cancel_check_call_host;
c->base.add_handshakers = ssl_channel_add_handshakers;
gpr_split_host_port(target_name, &c->target_name, &port);
gpr_free(port);
if (overridden_target_name != nullptr) {
c->overridden_target_name = gpr_strdup(overridden_target_name);
return GRPC_SECURITY_OK;
}
c->verify_options = &config->verify_options;
has_key_cert_pair = config->pem_key_cert_pair != nullptr &&
config->pem_key_cert_pair->private_key != nullptr &&
config->pem_key_cert_pair->cert_chain != nullptr;
if (has_key_cert_pair) {
options.pem_key_cert_pair = config->pem_key_cert_pair;
void add_handshakers(grpc_pollset_set* interested_parties,
grpc_handshake_manager* handshake_mgr) override {
// Instantiate TSI handshaker.
try_fetch_ssl_server_credentials();
tsi_handshaker* tsi_hs = nullptr;
tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
server_handshaker_factory_, &tsi_hs);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
return;
}
// Create handshakers.
grpc_handshake_manager_add(handshake_mgr,
grpc_security_handshaker_create(tsi_hs, this));
}
options.cipher_suites = grpc_get_ssl_cipher_suites();
options.session_cache = ssl_session_cache;
result = tsi_create_ssl_client_handshaker_factory_with_options(
&options, &c->client_handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
ssl_channel_destroy(&c->base.base);
*sc = nullptr;
goto error;
void check_peer(tsi_peer peer, grpc_endpoint* ep,
grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
grpc_closure* on_peer_checked) override {
grpc_error* error = ssl_check_peer(nullptr, &peer, auth_context);
tsi_peer_destruct(&peer);
GRPC_CLOSURE_SCHED(on_peer_checked, error);
}
*sc = &c->base;
gpr_free((void*)options.alpn_protocols);
return GRPC_SECURITY_OK;
error:
gpr_free((void*)options.alpn_protocols);
return GRPC_SECURITY_ERROR;
}
int cmp(const grpc_security_connector* other) const override {
return server_security_connector_cmp(
static_cast<const grpc_server_security_connector*>(other));
}
static grpc_ssl_server_security_connector*
grpc_ssl_server_security_connector_initialize(
grpc_server_credentials* server_creds) {
grpc_ssl_server_security_connector* c =
static_cast<grpc_ssl_server_security_connector*>(
gpr_zalloc(sizeof(grpc_ssl_server_security_connector)));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.base.vtable = &ssl_server_vtable;
c->base.add_handshakers = ssl_server_add_handshakers;
c->base.server_creds = grpc_server_credentials_ref(server_creds);
return c;
}
private:
/* Attempts to fetch the server certificate config if a callback is available.
* Current certificate config will continue to be used if the callback returns
* an error. Returns true if new credentials were sucessfully loaded. */
bool try_fetch_ssl_server_credentials() {
grpc_ssl_server_certificate_config* certificate_config = nullptr;
bool status;
if (!has_cert_config_fetcher()) return false;
grpc_ssl_server_credentials* server_creds =
static_cast<grpc_ssl_server_credentials*>(this->mutable_server_creds());
grpc_ssl_certificate_config_reload_status cb_result =
server_creds->FetchCertConfig(&certificate_config);
if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) {
gpr_log(GPR_DEBUG, "No change in SSL server credentials.");
status = false;
} else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) {
status = try_replace_server_handshaker_factory(certificate_config);
} else {
// Log error, continue using previously-loaded credentials.
gpr_log(GPR_ERROR,
"Failed fetching new server credentials, continuing to "
"use previously-loaded credentials.");
status = false;
}
grpc_security_status grpc_ssl_server_security_connector_create(
grpc_server_credentials* gsc, grpc_server_security_connector** sc) {
tsi_result result = TSI_OK;
grpc_ssl_server_credentials* server_credentials =
reinterpret_cast<grpc_ssl_server_credentials*>(gsc);
grpc_security_status retval = GRPC_SECURITY_OK;
if (certificate_config != nullptr) {
grpc_ssl_server_certificate_config_destroy(certificate_config);
}
return status;
}
GPR_ASSERT(server_credentials != nullptr);
GPR_ASSERT(sc != nullptr);
grpc_ssl_server_security_connector* c =
grpc_ssl_server_security_connector_initialize(gsc);
if (server_connector_has_cert_config_fetcher(c)) {
// Load initial credentials from certificate_config_fetcher:
if (!try_fetch_ssl_server_credentials(c)) {
gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher.");
retval = GRPC_SECURITY_ERROR;
/* Attempts to replace the server_handshaker_factory with a new factory using
* the provided grpc_ssl_server_certificate_config. Should new factory
* creation fail, the existing factory will not be replaced. Returns true on
* success (new factory created). */
bool try_replace_server_handshaker_factory(
const grpc_ssl_server_certificate_config* config) {
if (config == nullptr) {
gpr_log(GPR_ERROR,
"Server certificate config callback returned invalid (NULL) "
"config.");
return false;
}
} else {
gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config);
size_t num_alpn_protocols = 0;
const char** alpn_protocol_strings =
grpc_fill_alpn_protocol_strings(&num_alpn_protocols);
result = tsi_create_ssl_server_handshaker_factory_ex(
server_credentials->config.pem_key_cert_pairs,
server_credentials->config.num_key_cert_pairs,
server_credentials->config.pem_root_certs,
tsi_ssl_pem_key_cert_pair* cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs(
config->pem_key_cert_pairs, config->num_key_cert_pairs);
tsi_ssl_server_handshaker_factory* new_handshaker_factory = nullptr;
const grpc_ssl_server_credentials* server_creds =
static_cast<const grpc_ssl_server_credentials*>(this->server_creds());
GPR_DEBUG_ASSERT(config->pem_root_certs != nullptr);
tsi_result result = tsi_create_ssl_server_handshaker_factory_ex(
cert_pairs, config->num_key_cert_pairs, config->pem_root_certs,
grpc_get_tsi_client_certificate_request_type(
server_credentials->config.client_certificate_request),
server_creds->config().client_certificate_request),
grpc_get_ssl_cipher_suites(), alpn_protocol_strings,
static_cast<uint16_t>(num_alpn_protocols),
&c->server_handshaker_factory);
static_cast<uint16_t>(num_alpn_protocols), &new_handshaker_factory);
gpr_free(cert_pairs);
gpr_free((void*)alpn_protocol_strings);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
retval = GRPC_SECURITY_ERROR;
return false;
}
set_server_handshaker_factory(new_handshaker_factory);
return true;
}
void set_server_handshaker_factory(
tsi_ssl_server_handshaker_factory* new_factory) {
if (server_handshaker_factory_) {
tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_);
}
server_handshaker_factory_ = new_factory;
}
tsi_ssl_server_handshaker_factory* server_handshaker_factory_ = nullptr;
};
} // namespace
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_ssl_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const grpc_ssl_config* config, const char* target_name,
const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache) {
if (config == nullptr || target_name == nullptr) {
gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
return nullptr;
}
if (retval == GRPC_SECURITY_OK) {
*sc = &c->base;
const char* pem_root_certs;
const tsi_ssl_root_certs_store* root_store;
if (config->pem_root_certs == nullptr) {
// Use default root certificates.
pem_root_certs = grpc_core::DefaultSslRootStore::GetPemRootCerts();
if (pem_root_certs == nullptr) {
gpr_log(GPR_ERROR, "Could not get default pem root certs.");
return nullptr;
}
root_store = grpc_core::DefaultSslRootStore::GetRootStore();
} else {
if (c != nullptr) ssl_server_destroy(&c->base.base);
if (sc != nullptr) *sc = nullptr;
pem_root_certs = config->pem_root_certs;
root_store = nullptr;
}
grpc_core::RefCountedPtr<grpc_ssl_channel_security_connector> c =
grpc_core::MakeRefCounted<grpc_ssl_channel_security_connector>(
std::move(channel_creds), std::move(request_metadata_creds), config,
target_name, overridden_target_name);
const grpc_security_status result = c->InitializeHandshakerFactory(
config, pem_root_certs, root_store, ssl_session_cache);
if (result != GRPC_SECURITY_OK) {
return nullptr;
}
return retval;
return c;
}
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_ssl_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_credentials) {
GPR_ASSERT(server_credentials != nullptr);
grpc_core::RefCountedPtr<grpc_ssl_server_security_connector> c =
grpc_core::MakeRefCounted<grpc_ssl_server_security_connector>(
std::move(server_credentials));
const grpc_security_status retval = c->InitializeHandshakerFactory();
if (retval != GRPC_SECURITY_OK) {
return nullptr;
}
return c;
}

@ -25,6 +25,7 @@
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
@ -47,20 +48,21 @@ typedef struct {
This function returns GRPC_SECURITY_OK in case of success or a
specific error code otherwise.
*/
grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_channel_credentials* channel_creds,
grpc_call_credentials* request_metadata_creds,
grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_ssl_channel_security_connector_create(
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
const grpc_ssl_config* config, const char* target_name,
const char* overridden_target_name,
tsi_ssl_session_cache* ssl_session_cache,
grpc_channel_security_connector** sc);
tsi_ssl_session_cache* ssl_session_cache);
/* Config for ssl servers. */
typedef struct {
tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs;
size_t num_key_cert_pairs;
char* pem_root_certs;
grpc_ssl_client_certificate_request_type client_certificate_request;
tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs = nullptr;
size_t num_key_cert_pairs = 0;
char* pem_root_certs = nullptr;
grpc_ssl_client_certificate_request_type client_certificate_request =
GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
} grpc_ssl_server_config;
/* Creates an SSL server_security_connector.
@ -69,9 +71,9 @@ typedef struct {
This function returns GRPC_SECURITY_OK in case of success or a
specific error code otherwise.
*/
grpc_security_status grpc_ssl_server_security_connector_create(
grpc_server_credentials* server_credentials,
grpc_server_security_connector** sc);
grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_ssl_server_security_connector_create(
grpc_core::RefCountedPtr<grpc_server_credentials> server_credentials);
#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_SSL_SSL_SECURITY_CONNECTOR_H \
*/

@ -30,6 +30,7 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/security_connector/load_system_roots.h"
@ -141,16 +142,17 @@ int grpc_ssl_host_matches_name(const tsi_peer* peer, const char* peer_name) {
return r;
}
grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) {
grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
const tsi_peer* peer) {
size_t i;
grpc_auth_context* ctx = nullptr;
const char* peer_identity_property_name = nullptr;
/* The caller has checked the certificate type property. */
GPR_ASSERT(peer->property_count >= 1);
ctx = grpc_auth_context_create(nullptr);
grpc_core::RefCountedPtr<grpc_auth_context> ctx =
grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
grpc_auth_context_add_cstring_property(
ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
for (i = 0; i < peer->property_count; i++) {
const tsi_peer_property* prop = &peer->properties[i];
@ -160,24 +162,26 @@ grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) {
if (peer_identity_property_name == nullptr) {
peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
}
grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME,
grpc_auth_context_add_property(ctx.get(), GRPC_X509_CN_PROPERTY_NAME,
prop->value.data, prop->value.length);
} else if (strcmp(prop->name,
TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
grpc_auth_context_add_property(ctx.get(), GRPC_X509_SAN_PROPERTY_NAME,
prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
grpc_auth_context_add_property(ctx.get(),
GRPC_X509_PEM_CERT_PROPERTY_NAME,
prop->value.data, prop->value.length);
} else if (strcmp(prop->name, TSI_SSL_SESSION_REUSED_PEER_PROPERTY) == 0) {
grpc_auth_context_add_property(ctx, GRPC_SSL_SESSION_REUSED_PROPERTY,
grpc_auth_context_add_property(ctx.get(),
GRPC_SSL_SESSION_REUSED_PROPERTY,
prop->value.data, prop->value.length);
}
}
if (peer_identity_property_name != nullptr) {
GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
ctx, peer_identity_property_name) == 1);
ctx.get(), peer_identity_property_name) == 1);
}
return ctx;
}

@ -26,6 +26,7 @@
#include <grpc/grpc_security.h>
#include <grpc/slice_buffer.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
@ -47,7 +48,8 @@ grpc_get_tsi_client_certificate_request_type(
const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols);
/* Exposed for testing only. */
grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer);
grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(
const tsi_peer* peer);
tsi_peer grpc_shallow_peer_from_ssl_auth_context(
const grpc_auth_context* auth_context);
void grpc_shallow_peer_destruct(tsi_peer* peer);

@ -55,7 +55,7 @@ struct call_data {
// that the memory is not initialized.
void destroy() {
grpc_credentials_mdelem_array_destroy(&md_array);
grpc_call_credentials_unref(creds);
creds.reset();
grpc_slice_unref_internal(host);
grpc_slice_unref_internal(method);
grpc_auth_metadata_context_reset(&auth_md_context);
@ -64,7 +64,7 @@ struct call_data {
gpr_arena* arena;
grpc_call_stack* owning_call;
grpc_call_combiner* call_combiner;
grpc_call_credentials* creds = nullptr;
grpc_core::RefCountedPtr<grpc_call_credentials> creds;
grpc_slice host = grpc_empty_slice();
grpc_slice method = grpc_empty_slice();
/* pollset{_set} bound to this call; if we need to make external
@ -83,8 +83,18 @@ struct call_data {
/* We can have a per-channel credentials. */
struct channel_data {
grpc_channel_security_connector* security_connector;
grpc_auth_context* auth_context;
channel_data(grpc_channel_security_connector* security_connector,
grpc_auth_context* auth_context)
: security_connector(
security_connector->Ref(DEBUG_LOCATION, "client_auth_filter")),
auth_context(auth_context->Ref(DEBUG_LOCATION, "client_auth_filter")) {}
~channel_data() {
security_connector.reset(DEBUG_LOCATION, "client_auth_filter");
auth_context.reset(DEBUG_LOCATION, "client_auth_filter");
}
grpc_core::RefCountedPtr<grpc_channel_security_connector> security_connector;
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
};
} // namespace
@ -98,10 +108,11 @@ void grpc_auth_metadata_context_reset(
gpr_free(const_cast<char*>(auth_md_context->method_name));
auth_md_context->method_name = nullptr;
}
GRPC_AUTH_CONTEXT_UNREF(
(grpc_auth_context*)auth_md_context->channel_auth_context,
"grpc_auth_metadata_context");
auth_md_context->channel_auth_context = nullptr;
if (auth_md_context->channel_auth_context != nullptr) {
const_cast<grpc_auth_context*>(auth_md_context->channel_auth_context)
->Unref(DEBUG_LOCATION, "grpc_auth_metadata_context");
auth_md_context->channel_auth_context = nullptr;
}
}
static void add_error(grpc_error** combined, grpc_error* error) {
@ -175,7 +186,10 @@ void grpc_auth_metadata_context_build(
auth_md_context->service_url = service_url;
auth_md_context->method_name = method_name;
auth_md_context->channel_auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context");
auth_context == nullptr
? nullptr
: auth_context->Ref(DEBUG_LOCATION, "grpc_auth_metadata_context")
.release();
gpr_free(service);
gpr_free(host_and_port);
}
@ -184,8 +198,8 @@ static void cancel_get_request_metadata(void* arg, grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
call_data* calld = static_cast<call_data*>(elem->call_data);
if (error != GRPC_ERROR_NONE) {
grpc_call_credentials_cancel_get_request_metadata(
calld->creds, &calld->md_array, GRPC_ERROR_REF(error));
calld->creds->cancel_get_request_metadata(&calld->md_array,
GRPC_ERROR_REF(error));
}
}
@ -197,7 +211,7 @@ static void send_security_metadata(grpc_call_element* elem,
static_cast<grpc_client_security_context*>(
batch->payload->context[GRPC_CONTEXT_SECURITY].value);
grpc_call_credentials* channel_call_creds =
chand->security_connector->request_metadata_creds;
chand->security_connector->mutable_request_metadata_creds();
int call_creds_has_md = (ctx != nullptr) && (ctx->creds != nullptr);
if (channel_call_creds == nullptr && !call_creds_has_md) {
@ -207,8 +221,9 @@ static void send_security_metadata(grpc_call_element* elem,
}
if (channel_call_creds != nullptr && call_creds_has_md) {
calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
ctx->creds, nullptr);
calld->creds = grpc_core::RefCountedPtr<grpc_call_credentials>(
grpc_composite_call_credentials_create(channel_call_creds,
ctx->creds.get(), nullptr));
if (calld->creds == nullptr) {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
@ -220,22 +235,22 @@ static void send_security_metadata(grpc_call_element* elem,
return;
}
} else {
calld->creds = grpc_call_credentials_ref(
call_creds_has_md ? ctx->creds : channel_call_creds);
calld->creds =
call_creds_has_md ? ctx->creds->Ref() : channel_call_creds->Ref();
}
grpc_auth_metadata_context_build(
chand->security_connector->base.url_scheme, calld->host, calld->method,
chand->auth_context, &calld->auth_md_context);
chand->security_connector->url_scheme(), calld->host, calld->method,
chand->auth_context.get(), &calld->auth_md_context);
GPR_ASSERT(calld->pollent != nullptr);
GRPC_CALL_STACK_REF(calld->owning_call, "get_request_metadata");
GRPC_CLOSURE_INIT(&calld->async_result_closure, on_credentials_metadata,
batch, grpc_schedule_on_exec_ctx);
grpc_error* error = GRPC_ERROR_NONE;
if (grpc_call_credentials_get_request_metadata(
calld->creds, calld->pollent, calld->auth_md_context,
&calld->md_array, &calld->async_result_closure, &error)) {
if (calld->creds->get_request_metadata(
calld->pollent, calld->auth_md_context, &calld->md_array,
&calld->async_result_closure, &error)) {
// Synchronous return; invoke on_credentials_metadata() directly.
on_credentials_metadata(batch, error);
GRPC_ERROR_UNREF(error);
@ -279,9 +294,8 @@ static void cancel_check_call_host(void* arg, grpc_error* error) {
call_data* calld = static_cast<call_data*>(elem->call_data);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
if (error != GRPC_ERROR_NONE) {
grpc_channel_security_connector_cancel_check_call_host(
chand->security_connector, &calld->async_result_closure,
GRPC_ERROR_REF(error));
chand->security_connector->cancel_check_call_host(
&calld->async_result_closure, GRPC_ERROR_REF(error));
}
}
@ -299,16 +313,16 @@ static void auth_start_transport_stream_op_batch(
GPR_ASSERT(batch->payload->context != nullptr);
if (batch->payload->context[GRPC_CONTEXT_SECURITY].value == nullptr) {
batch->payload->context[GRPC_CONTEXT_SECURITY].value =
grpc_client_security_context_create(calld->arena);
grpc_client_security_context_create(calld->arena, /*creds=*/nullptr);
batch->payload->context[GRPC_CONTEXT_SECURITY].destroy =
grpc_client_security_context_destroy;
}
grpc_client_security_context* sec_ctx =
static_cast<grpc_client_security_context*>(
batch->payload->context[GRPC_CONTEXT_SECURITY].value);
GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
sec_ctx->auth_context.reset(DEBUG_LOCATION, "client_auth_filter");
sec_ctx->auth_context =
GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
chand->auth_context->Ref(DEBUG_LOCATION, "client_auth_filter");
}
if (batch->send_initial_metadata) {
@ -327,8 +341,8 @@ static void auth_start_transport_stream_op_batch(
grpc_schedule_on_exec_ctx);
char* call_host = grpc_slice_to_c_string(calld->host);
grpc_error* error = GRPC_ERROR_NONE;
if (grpc_channel_security_connector_check_call_host(
chand->security_connector, call_host, chand->auth_context,
if (chand->security_connector->check_call_host(
call_host, chand->auth_context.get(),
&calld->async_result_closure, &error)) {
// Synchronous return; invoke on_host_checked() directly.
on_host_checked(batch, error);
@ -374,6 +388,10 @@ static void destroy_call_elem(grpc_call_element* elem,
/* Constructor for channel_data */
static grpc_error* init_channel_elem(grpc_channel_element* elem,
grpc_channel_element_args* args) {
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!args->is_last);
grpc_security_connector* sc =
grpc_security_connector_find_in_args(args->channel_args);
if (sc == nullptr) {
@ -386,33 +404,15 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem,
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Auth context missing from client auth filter args");
}
/* grab pointers to our data from the channel element */
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!args->is_last);
/* initialize members */
chand->security_connector =
reinterpret_cast<grpc_channel_security_connector*>(
GRPC_SECURITY_CONNECTOR_REF(sc, "client_auth_filter"));
chand->auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
new (elem->channel_data) channel_data(
static_cast<grpc_channel_security_connector*>(sc), auth_context);
return GRPC_ERROR_NONE;
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element* elem) {
/* grab pointers to our data from the channel element */
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
grpc_channel_security_connector* sc = chand->security_connector;
if (sc != nullptr) {
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter");
}
GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter");
chand->~channel_data();
}
const grpc_channel_filter grpc_client_auth_filter = {

@ -30,6 +30,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/tsi_error.h"
@ -38,34 +39,62 @@
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
typedef struct {
namespace {
struct security_handshaker {
security_handshaker(tsi_handshaker* handshaker,
grpc_security_connector* connector);
~security_handshaker() {
gpr_mu_destroy(&mu);
tsi_handshaker_destroy(handshaker);
tsi_handshaker_result_destroy(handshaker_result);
if (endpoint_to_destroy != nullptr) {
grpc_endpoint_destroy(endpoint_to_destroy);
}
if (read_buffer_to_destroy != nullptr) {
grpc_slice_buffer_destroy_internal(read_buffer_to_destroy);
gpr_free(read_buffer_to_destroy);
}
gpr_free(handshake_buffer);
grpc_slice_buffer_destroy_internal(&outgoing);
auth_context.reset(DEBUG_LOCATION, "handshake");
connector.reset(DEBUG_LOCATION, "handshake");
}
void Ref() { refs.Ref(); }
void Unref() {
if (refs.Unref()) {
grpc_core::Delete(this);
}
}
grpc_handshaker base;
// State set at creation time.
tsi_handshaker* handshaker;
grpc_security_connector* connector;
grpc_core::RefCountedPtr<grpc_security_connector> connector;
gpr_mu mu;
gpr_refcount refs;
grpc_core::RefCount refs;
bool shutdown;
bool shutdown = false;
// Endpoint and read buffer to destroy after a shutdown.
grpc_endpoint* endpoint_to_destroy;
grpc_slice_buffer* read_buffer_to_destroy;
grpc_endpoint* endpoint_to_destroy = nullptr;
grpc_slice_buffer* read_buffer_to_destroy = nullptr;
// State saved while performing the handshake.
grpc_handshaker_args* args;
grpc_closure* on_handshake_done;
grpc_handshaker_args* args = nullptr;
grpc_closure* on_handshake_done = nullptr;
unsigned char* handshake_buffer;
size_t handshake_buffer_size;
unsigned char* handshake_buffer;
grpc_slice_buffer outgoing;
grpc_closure on_handshake_data_sent_to_peer;
grpc_closure on_handshake_data_received_from_peer;
grpc_closure on_peer_checked;
grpc_auth_context* auth_context;
tsi_handshaker_result* handshaker_result;
} security_handshaker;
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
tsi_handshaker_result* handshaker_result = nullptr;
};
} // namespace
static size_t move_read_buffer_into_handshake_buffer(security_handshaker* h) {
size_t bytes_in_read_buffer = h->args->read_buffer->length;
@ -85,26 +114,6 @@ static size_t move_read_buffer_into_handshake_buffer(security_handshaker* h) {
return bytes_in_read_buffer;
}
static void security_handshaker_unref(security_handshaker* h) {
if (gpr_unref(&h->refs)) {
gpr_mu_destroy(&h->mu);
tsi_handshaker_destroy(h->handshaker);
tsi_handshaker_result_destroy(h->handshaker_result);
if (h->endpoint_to_destroy != nullptr) {
grpc_endpoint_destroy(h->endpoint_to_destroy);
}
if (h->read_buffer_to_destroy != nullptr) {
grpc_slice_buffer_destroy_internal(h->read_buffer_to_destroy);
gpr_free(h->read_buffer_to_destroy);
}
gpr_free(h->handshake_buffer);
grpc_slice_buffer_destroy_internal(&h->outgoing);
GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
gpr_free(h);
}
}
// Set args fields to NULL, saving the endpoint and read buffer for
// later destruction.
static void cleanup_args_for_failure_locked(security_handshaker* h) {
@ -194,7 +203,7 @@ static void on_peer_checked_inner(security_handshaker* h, grpc_error* error) {
tsi_handshaker_result_destroy(h->handshaker_result);
h->handshaker_result = nullptr;
// Add auth context to channel args.
grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context);
grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context.get());
grpc_channel_args* tmp_args = h->args->args;
h->args->args =
grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1);
@ -211,7 +220,7 @@ static void on_peer_checked(void* arg, grpc_error* error) {
gpr_mu_lock(&h->mu);
on_peer_checked_inner(h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
}
static grpc_error* check_peer_locked(security_handshaker* h) {
@ -222,8 +231,8 @@ static grpc_error* check_peer_locked(security_handshaker* h) {
return grpc_set_tsi_error_result(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), result);
}
grpc_security_connector_check_peer(h->connector, peer, &h->auth_context,
&h->on_peer_checked);
h->connector->check_peer(peer, h->args->endpoint, &h->auth_context,
&h->on_peer_checked);
return GRPC_ERROR_NONE;
}
@ -281,7 +290,7 @@ static void on_handshake_next_done_grpc_wrapper(
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
} else {
gpr_mu_unlock(&h->mu);
}
@ -317,7 +326,7 @@ static void on_handshake_data_received_from_peer(void* arg, grpc_error* error) {
h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Handshake read failed", &error, 1));
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
return;
}
// Copy all slices received.
@ -329,7 +338,7 @@ static void on_handshake_data_received_from_peer(void* arg, grpc_error* error) {
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
} else {
gpr_mu_unlock(&h->mu);
}
@ -343,7 +352,7 @@ static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) {
h, GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Handshake write failed", &error, 1));
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
return;
}
// We may be done.
@ -355,7 +364,7 @@ static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) {
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
return;
}
}
@ -368,7 +377,7 @@ static void on_handshake_data_sent_to_peer(void* arg, grpc_error* error) {
static void security_handshaker_destroy(grpc_handshaker* handshaker) {
security_handshaker* h = reinterpret_cast<security_handshaker*>(handshaker);
security_handshaker_unref(h);
h->Unref();
}
static void security_handshaker_shutdown(grpc_handshaker* handshaker,
@ -393,14 +402,14 @@ static void security_handshaker_do_handshake(grpc_handshaker* handshaker,
gpr_mu_lock(&h->mu);
h->args = args;
h->on_handshake_done = on_handshake_done;
gpr_ref(&h->refs);
h->Ref();
size_t bytes_received_size = move_read_buffer_into_handshake_buffer(h);
grpc_error* error =
do_handshaker_next_locked(h, h->handshake_buffer, bytes_received_size);
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(h);
h->Unref();
return;
}
gpr_mu_unlock(&h->mu);
@ -410,27 +419,32 @@ static const grpc_handshaker_vtable security_handshaker_vtable = {
security_handshaker_destroy, security_handshaker_shutdown,
security_handshaker_do_handshake, "security"};
static grpc_handshaker* security_handshaker_create(
tsi_handshaker* handshaker, grpc_security_connector* connector) {
security_handshaker* h = static_cast<security_handshaker*>(
gpr_zalloc(sizeof(security_handshaker)));
grpc_handshaker_init(&security_handshaker_vtable, &h->base);
h->handshaker = handshaker;
h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
gpr_mu_init(&h->mu);
gpr_ref_init(&h->refs, 1);
h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
h->handshake_buffer =
static_cast<uint8_t*>(gpr_malloc(h->handshake_buffer_size));
GRPC_CLOSURE_INIT(&h->on_handshake_data_sent_to_peer,
on_handshake_data_sent_to_peer, h,
namespace {
security_handshaker::security_handshaker(tsi_handshaker* handshaker,
grpc_security_connector* connector)
: handshaker(handshaker),
connector(connector->Ref(DEBUG_LOCATION, "handshake")),
handshake_buffer_size(GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE),
handshake_buffer(
static_cast<uint8_t*>(gpr_malloc(handshake_buffer_size))) {
grpc_handshaker_init(&security_handshaker_vtable, &base);
gpr_mu_init(&mu);
grpc_slice_buffer_init(&outgoing);
GRPC_CLOSURE_INIT(&on_handshake_data_sent_to_peer,
::on_handshake_data_sent_to_peer, this,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&h->on_handshake_data_received_from_peer,
on_handshake_data_received_from_peer, h,
GRPC_CLOSURE_INIT(&on_handshake_data_received_from_peer,
::on_handshake_data_received_from_peer, this,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&h->on_peer_checked, on_peer_checked, h,
GRPC_CLOSURE_INIT(&on_peer_checked, ::on_peer_checked, this,
grpc_schedule_on_exec_ctx);
grpc_slice_buffer_init(&h->outgoing);
}
} // namespace
static grpc_handshaker* security_handshaker_create(
tsi_handshaker* handshaker, grpc_security_connector* connector) {
security_handshaker* h =
grpc_core::New<security_handshaker>(handshaker, connector);
return &h->base;
}
@ -477,8 +491,9 @@ static void client_handshaker_factory_add_handshakers(
grpc_channel_security_connector* security_connector =
reinterpret_cast<grpc_channel_security_connector*>(
grpc_security_connector_find_in_args(args));
grpc_channel_security_connector_add_handshakers(
security_connector, interested_parties, handshake_mgr);
if (security_connector) {
security_connector->add_handshakers(interested_parties, handshake_mgr);
}
}
static void server_handshaker_factory_add_handshakers(
@ -488,8 +503,9 @@ static void server_handshaker_factory_add_handshakers(
grpc_server_security_connector* security_connector =
reinterpret_cast<grpc_server_security_connector*>(
grpc_security_connector_find_in_args(args));
grpc_server_security_connector_add_handshakers(
security_connector, interested_parties, handshake_mgr);
if (security_connector) {
security_connector->add_handshakers(interested_parties, handshake_mgr);
}
}
static void handshaker_factory_destroy(

@ -39,8 +39,12 @@ enum async_state {
};
struct channel_data {
grpc_auth_context* auth_context;
grpc_server_credentials* creds;
channel_data(grpc_auth_context* auth_context, grpc_server_credentials* creds)
: auth_context(auth_context->Ref()), creds(creds->Ref()) {}
~channel_data() { auth_context.reset(DEBUG_LOCATION, "server_auth_filter"); }
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
grpc_core::RefCountedPtr<grpc_server_credentials> creds;
};
struct call_data {
@ -58,7 +62,7 @@ struct call_data {
grpc_server_security_context_create(args.arena);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
server_ctx->auth_context =
GRPC_AUTH_CONTEXT_REF(chand->auth_context, "server_auth_filter");
chand->auth_context->Ref(DEBUG_LOCATION, "server_auth_filter");
if (args.context[GRPC_CONTEXT_SECURITY].value != nullptr) {
args.context[GRPC_CONTEXT_SECURITY].destroy(
args.context[GRPC_CONTEXT_SECURITY].value);
@ -208,7 +212,8 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
call_data* calld = static_cast<call_data*>(elem->call_data);
grpc_transport_stream_op_batch* batch = calld->recv_initial_metadata_batch;
if (error == GRPC_ERROR_NONE) {
if (chand->creds != nullptr && chand->creds->processor.process != nullptr) {
if (chand->creds != nullptr &&
chand->creds->auth_metadata_processor().process != nullptr) {
// We're calling out to the application, so we need to make sure
// to drop the call combiner early if we get cancelled.
GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem,
@ -218,9 +223,10 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
GRPC_CALL_STACK_REF(calld->owning_call, "server_auth_metadata");
calld->md = metadata_batch_to_md_array(
batch->payload->recv_initial_metadata.recv_initial_metadata);
chand->creds->processor.process(
chand->creds->processor.state, chand->auth_context,
calld->md.metadata, calld->md.count, on_md_processing_done, elem);
chand->creds->auth_metadata_processor().process(
chand->creds->auth_metadata_processor().state,
chand->auth_context.get(), calld->md.metadata, calld->md.count,
on_md_processing_done, elem);
return;
}
}
@ -290,23 +296,19 @@ static void destroy_call_elem(grpc_call_element* elem,
static grpc_error* init_channel_elem(grpc_channel_element* elem,
grpc_channel_element_args* args) {
GPR_ASSERT(!args->is_last);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
grpc_auth_context* auth_context =
grpc_find_auth_context_in_args(args->channel_args);
GPR_ASSERT(auth_context != nullptr);
chand->auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
grpc_server_credentials* creds =
grpc_find_server_credentials_in_args(args->channel_args);
chand->creds = grpc_server_credentials_ref(creds);
new (elem->channel_data) channel_data(auth_context, creds);
return GRPC_ERROR_NONE;
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element* elem) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
grpc_server_credentials_unref(chand->creds);
chand->~channel_data();
}
const grpc_channel_filter grpc_server_auth_filter = {

@ -156,9 +156,13 @@ static unsigned long openssl_thread_id_cb(void) {
#endif
static void init_openssl(void) {
#if OPENSSL_API_COMPAT >= 0x10100000L
OPENSSL_init_ssl(0, NULL);
#else
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000
if (!CRYPTO_get_locking_callback()) {
int num_locks = CRYPTO_num_locks();
@ -1649,7 +1653,11 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
return TSI_INVALID_ARGUMENT;
}
#if defined(OPENSSL_NO_TLS1_2_METHOD) || OPENSSL_API_COMPAT >= 0x10100000L
ssl_context = SSL_CTX_new(TLS_method());
#else
ssl_context = SSL_CTX_new(TLSv1_2_method());
#endif
if (ssl_context == nullptr) {
gpr_log(GPR_ERROR, "Could not create ssl context.");
return TSI_INVALID_ARGUMENT;
@ -1806,7 +1814,11 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
for (i = 0; i < options->num_key_cert_pairs; i++) {
do {
#if defined(OPENSSL_NO_TLS1_2_METHOD) || OPENSSL_API_COMPAT >= 0x10100000L
impl->ssl_contexts[i] = SSL_CTX_new(TLS_method());
#else
impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
#endif
if (impl->ssl_contexts[i] == nullptr) {
gpr_log(GPR_ERROR, "Could not create ssl context.");
result = TSI_OUT_OF_RESOURCES;
@ -1850,31 +1862,30 @@ tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
break;
}
SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
switch (options->client_certificate_request) {
case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr);
break;
case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER,
NullVerifyCallback);
break;
case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, nullptr);
break;
case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
SSL_CTX_set_verify(
impl->ssl_contexts[i],
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NullVerifyCallback);
break;
case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
SSL_CTX_set_verify(
impl->ssl_contexts[i],
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
break;
}
/* TODO(jboeuf): Add revocation verification. */
}
switch (options->client_certificate_request) {
case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr);
break;
case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER,
NullVerifyCallback);
break;
case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, nullptr);
break;
case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
SSL_CTX_set_verify(impl->ssl_contexts[i],
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NullVerifyCallback);
break;
case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
SSL_CTX_set_verify(impl->ssl_contexts[i],
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
nullptr);
break;
}
/* TODO(jboeuf): Add revocation verification. */
result = extract_x509_subject_names_from_pem_cert(
options->pem_key_cert_pairs[i].cert_chain,

@ -261,10 +261,10 @@ void MetadataCredentialsPluginWrapper::InvokePlugin(
grpc_status_code* status_code, const char** error_details) {
std::multimap<grpc::string, grpc::string> metadata;
// const_cast is safe since the SecureAuthContext does not take owndership and
// the object is passed as a const ref to plugin_->GetMetadata.
// const_cast is safe since the SecureAuthContext only inc/dec the refcount
// and the object is passed as a const ref to plugin_->GetMetadata.
SecureAuthContext cpp_channel_auth_context(
const_cast<grpc_auth_context*>(context.channel_auth_context), false);
const_cast<grpc_auth_context*>(context.channel_auth_context));
Status status = plugin_->GetMetadata(context.service_url, context.method_name,
cpp_channel_auth_context, &metadata);

@ -24,6 +24,7 @@
#include <grpcpp/security/credentials.h>
#include <grpcpp/support/config.h>
#include "src/core/lib/security/credentials/credentials.h"
#include "src/cpp/server/thread_pool_interface.h"
namespace grpc {
@ -31,7 +32,9 @@ namespace grpc {
class SecureChannelCredentials final : public ChannelCredentials {
public:
explicit SecureChannelCredentials(grpc_channel_credentials* c_creds);
~SecureChannelCredentials() { grpc_channel_credentials_release(c_creds_); }
~SecureChannelCredentials() {
if (c_creds_ != nullptr) c_creds_->Unref();
}
grpc_channel_credentials* GetRawCreds() { return c_creds_; }
std::shared_ptr<grpc::Channel> CreateChannel(
@ -51,7 +54,9 @@ class SecureChannelCredentials final : public ChannelCredentials {
class SecureCallCredentials final : public CallCredentials {
public:
explicit SecureCallCredentials(grpc_call_credentials* c_creds);
~SecureCallCredentials() { grpc_call_credentials_release(c_creds_); }
~SecureCallCredentials() {
if (c_creds_ != nullptr) c_creds_->Unref();
}
grpc_call_credentials* GetRawCreds() { return c_creds_; }
bool ApplyToCall(grpc_call* call) override;

@ -31,10 +31,10 @@
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
namespace grpc {
namespace grpc_impl {
namespace internal {
class AlarmImpl : public CompletionQueueTag {
class AlarmImpl : public ::grpc::internal::CompletionQueueTag {
public:
AlarmImpl() : cq_(nullptr), tag_(nullptr) {
gpr_ref_init(&refs_, 1);
@ -51,7 +51,7 @@ class AlarmImpl : public CompletionQueueTag {
Unref();
return true;
}
void Set(CompletionQueue* cq, gpr_timespec deadline, void* tag) {
void Set(::grpc::CompletionQueue* cq, gpr_timespec deadline, void* tag) {
grpc_core::ExecCtx exec_ctx;
GRPC_CQ_INTERNAL_REF(cq->cq(), "alarm");
cq_ = cq->cq();
@ -114,13 +114,14 @@ class AlarmImpl : public CompletionQueueTag {
};
} // namespace internal
static internal::GrpcLibraryInitializer g_gli_initializer;
static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer;
Alarm::Alarm() : alarm_(new internal::AlarmImpl()) {
g_gli_initializer.summon();
}
void Alarm::SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag) {
void Alarm::SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline,
void* tag) {
// Note that we know that alarm_ is actually an internal::AlarmImpl
// but we declared it as the base pointer to avoid a forward declaration
// or exposing core data structures in the C++ public headers.
@ -145,4 +146,4 @@ Alarm::~Alarm() {
}
void Alarm::Cancel() { static_cast<internal::AlarmImpl*>(alarm_)->Cancel(); }
} // namespace grpc
} // namespace grpc_impl

@ -22,19 +22,12 @@
namespace grpc {
SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx,
bool take_ownership)
: ctx_(ctx), take_ownership_(take_ownership) {}
SecureAuthContext::~SecureAuthContext() {
if (take_ownership_) grpc_auth_context_release(ctx_);
}
std::vector<grpc::string_ref> SecureAuthContext::GetPeerIdentity() const {
if (!ctx_) {
if (ctx_ == nullptr) {
return std::vector<grpc::string_ref>();
}
grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_);
grpc_auth_property_iterator iter =
grpc_auth_context_peer_identity(ctx_.get());
std::vector<grpc::string_ref> identity;
const grpc_auth_property* property = nullptr;
while ((property = grpc_auth_property_iterator_next(&iter))) {
@ -45,20 +38,20 @@ std::vector<grpc::string_ref> SecureAuthContext::GetPeerIdentity() const {
}
grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const {
if (!ctx_) {
if (ctx_ == nullptr) {
return "";
}
const char* name = grpc_auth_context_peer_identity_property_name(ctx_);
const char* name = grpc_auth_context_peer_identity_property_name(ctx_.get());
return name == nullptr ? "" : name;
}
std::vector<grpc::string_ref> SecureAuthContext::FindPropertyValues(
const grpc::string& name) const {
if (!ctx_) {
if (ctx_ == nullptr) {
return std::vector<grpc::string_ref>();
}
grpc_auth_property_iterator iter =
grpc_auth_context_find_properties_by_name(ctx_, name.c_str());
grpc_auth_context_find_properties_by_name(ctx_.get(), name.c_str());
const grpc_auth_property* property = nullptr;
std::vector<grpc::string_ref> values;
while ((property = grpc_auth_property_iterator_next(&iter))) {
@ -68,9 +61,9 @@ std::vector<grpc::string_ref> SecureAuthContext::FindPropertyValues(
}
AuthPropertyIterator SecureAuthContext::begin() const {
if (ctx_) {
if (ctx_ != nullptr) {
grpc_auth_property_iterator iter =
grpc_auth_context_property_iterator(ctx_);
grpc_auth_context_property_iterator(ctx_.get());
const grpc_auth_property* property =
grpc_auth_property_iterator_next(&iter);
return AuthPropertyIterator(property, &iter);
@ -85,19 +78,20 @@ AuthPropertyIterator SecureAuthContext::end() const {
void SecureAuthContext::AddProperty(const grpc::string& key,
const grpc::string_ref& value) {
if (!ctx_) return;
grpc_auth_context_add_property(ctx_, key.c_str(), value.data(), value.size());
if (ctx_ == nullptr) return;
grpc_auth_context_add_property(ctx_.get(), key.c_str(), value.data(),
value.size());
}
bool SecureAuthContext::SetPeerIdentityPropertyName(const grpc::string& name) {
if (!ctx_) return false;
return grpc_auth_context_set_peer_identity_property_name(ctx_,
if (ctx_ == nullptr) return false;
return grpc_auth_context_set_peer_identity_property_name(ctx_.get(),
name.c_str()) != 0;
}
bool SecureAuthContext::IsPeerAuthenticated() const {
if (!ctx_) return false;
return grpc_auth_context_peer_is_authenticated(ctx_) != 0;
if (ctx_ == nullptr) return false;
return grpc_auth_context_peer_is_authenticated(ctx_.get()) != 0;
}
} // namespace grpc

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save